aboutsummaryrefslogtreecommitdiff
path: root/docs/modules/ROOT/pages/basic_application.adoc
diff options
context:
space:
mode:
Diffstat (limited to 'docs/modules/ROOT/pages/basic_application.adoc')
-rw-r--r--docs/modules/ROOT/pages/basic_application.adoc75
1 files changed, 75 insertions, 0 deletions
diff --git a/docs/modules/ROOT/pages/basic_application.adoc b/docs/modules/ROOT/pages/basic_application.adoc
new file mode 100644
index 000000000..d56cb5e1d
--- /dev/null
+++ b/docs/modules/ROOT/pages/basic_application.adoc
@@ -0,0 +1,75 @@
1= A basic Embassy application
2
3So you've got one of the xref:examples.adoc[examples] running, but what now? Let's go through a simple Embassy application for the nRF52 DK to understand it better.
4
5
6== The Cargo.toml
7
8== The main
9
10=== Rust Nightly
11
12The first thing you'll notice is a few declarations stating that Embassy requires some nightly features:
13
14[source,rust]
15----
16#![no_std]
17#![no_main]
18#![feature(type_alias_impl_trait)]
19----
20
21=== Dealing with errors
22
23Then, what follows are some declarations on how to deal with panics and faults. During development, a good practice is to rely on `defmt-rtt` and `panic-probe` to print diagnostics to the terminal:
24
25[source,rust]
26----
27use defmt_rtt as _;
28use panic_probe as _;
29----
30
31=== Task declaration
32
33After a bit of import declaration, the tasks run by the application should be declared:
34
35[source,rust]
36----
37#[embassy::task]
38async fn blinker(led: Output<'static, P0_13>, interval: Duration) {
39 loop {
40 let _ = led.set_high();
41 Timer::after(interval).await;
42 let _ = led.set_low();
43 Timer::after(interval).await;
44 }
45}
46----
47
48An embassy task must be declared `async`, and may NOT take generic arguments. In this case, we are handed the LED that should be blinked and the interval of the blinking.
49
50NOTE: Notice that there is not busy waiting going on in this task. It is using the Embassy timer to yield execution, allowing the microcontroller to sleep in between the blinking.
51
52=== Main
53
54The main entry point of an Embassy application is defined using the `#[embassy::main]` macro. The entry point is also required to take a `Spawner` and a `Peripherals` argument.
55
56The `Spawner` is the way the main application spawns other tasks. The `Peripherals` type 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:
57
58[source, rust]
59----
60#[embassy::main]
61async fn main(spawner: Spawner, p: Peripherals) {
62 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
63 let _ = spawner.spawn(blinker(led, Duration::from_millis(300)));
64}
65----
66
67
68What happens when the `blinker` task have 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::main]` macro. The macro does the following:
69
70. Creates an Embassy Executor instance
71. Initializes the microcontroller to get the `Peripherals`
72. Defines a main task for the entry point
73. Runs the executor spawning the main task
74
75There is also a way to run the executor without using the macro, in which case you have to create the `Executor` instance yourself.