From c12337920f9bae4b3a775dd23964b1ad1607f866 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 9 Dec 2021 10:06:17 +0100 Subject: Initial PoC of embassy book --- docs/antora.yml | 5 +++++ docs/modules/ROOT/nav.adoc | 4 ++++ docs/modules/ROOT/pages/index.adoc | 24 ++++++++++++++++++++++++ docs/modules/ROOT/pages/nrf.adoc | 3 +++ docs/modules/ROOT/pages/runtime.adoc | 3 +++ docs/modules/ROOT/pages/stm32.adoc | 3 +++ docs/modules/ROOT/pages/traits.adoc | 3 +++ 7 files changed, 45 insertions(+) create mode 100644 docs/antora.yml create mode 100644 docs/modules/ROOT/nav.adoc create mode 100644 docs/modules/ROOT/pages/index.adoc create mode 100644 docs/modules/ROOT/pages/nrf.adoc create mode 100644 docs/modules/ROOT/pages/runtime.adoc create mode 100644 docs/modules/ROOT/pages/stm32.adoc create mode 100644 docs/modules/ROOT/pages/traits.adoc diff --git a/docs/antora.yml b/docs/antora.yml new file mode 100644 index 000000000..807c97c3f --- /dev/null +++ b/docs/antora.yml @@ -0,0 +1,5 @@ +name: embassy +title: Embassy +version: dev +nav: + - modules/ROOT/nav.adoc diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc new file mode 100644 index 000000000..228ead788 --- /dev/null +++ b/docs/modules/ROOT/nav.adoc @@ -0,0 +1,4 @@ +* xref:runtime.adoc[Runtime] +* xref:traits.adoc[Traits] +* xref:nrf.adoc[Nordic nRF HAL] +* xref:stm32.adoc[STM32 HAL] diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc new file mode 100644 index 000000000..5bc35ef43 --- /dev/null +++ b/docs/modules/ROOT/pages/index.adoc @@ -0,0 +1,24 @@ += Embassy + +Embassy is a project to make async/await a first-class option for embedded development. + +== Traits and types + +`embassy` provides a set of traits and types specifically designed for `async` usage. + +* `embassy::io`: `AsyncBufRead`, `AsyncWrite`. Traits for byte-stream IO, essentially `no_std` compatible versions of `futures::io`. +* `embassy::traits::flash`: Flash device trait. +* `embassy::time`: `Clock` and `Alarm` traits. Std-like `Duration` and `Instant`. +* More traits for SPI, I2C, UART async HAL coming soon. + +== Executor + +The `embassy::executor` module provides an async/await executor designed for embedded usage. + +* No `alloc`, no heap needed. Task futures are statically allocated. +* No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning. +* Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`. +* No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`. +* Efficient polling: a wake will only poll the woken task, not all of them. +* Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time. +* Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks. diff --git a/docs/modules/ROOT/pages/nrf.adoc b/docs/modules/ROOT/pages/nrf.adoc new file mode 100644 index 000000000..21c388f61 --- /dev/null +++ b/docs/modules/ROOT/pages/nrf.adoc @@ -0,0 +1,3 @@ += Embassy nRF HAL + +TODO diff --git a/docs/modules/ROOT/pages/runtime.adoc b/docs/modules/ROOT/pages/runtime.adoc new file mode 100644 index 000000000..2704f298b --- /dev/null +++ b/docs/modules/ROOT/pages/runtime.adoc @@ -0,0 +1,3 @@ += Embassy runtime + +TODO diff --git a/docs/modules/ROOT/pages/stm32.adoc b/docs/modules/ROOT/pages/stm32.adoc new file mode 100644 index 000000000..328f69e2a --- /dev/null +++ b/docs/modules/ROOT/pages/stm32.adoc @@ -0,0 +1,3 @@ += Embassy STM32 HAL + +TODO diff --git a/docs/modules/ROOT/pages/traits.adoc b/docs/modules/ROOT/pages/traits.adoc new file mode 100644 index 000000000..843cc293e --- /dev/null +++ b/docs/modules/ROOT/pages/traits.adoc @@ -0,0 +1,3 @@ += Embassy Traits + +TODO -- cgit From 5c4a9043d19cc457feaec3ce7b4f279dfac530e8 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 9 Dec 2021 10:40:26 +0100 Subject: Update docs --- docs/modules/ROOT/nav.adoc | 8 ++++---- docs/modules/ROOT/pages/examples.adoc | 3 +++ docs/modules/ROOT/pages/hal.adoc | 9 +++++++++ docs/modules/ROOT/pages/index.adoc | 21 ++++++--------------- docs/modules/ROOT/pages/runtime.adoc | 10 +++++++++- docs/modules/ROOT/pages/stm32.adoc | 3 --- docs/modules/ROOT/pages/traits.adoc | 7 ++++++- 7 files changed, 37 insertions(+), 24 deletions(-) create mode 100644 docs/modules/ROOT/pages/examples.adoc create mode 100644 docs/modules/ROOT/pages/hal.adoc delete mode 100644 docs/modules/ROOT/pages/stm32.adoc diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 228ead788..dbf9b0bae 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -1,4 +1,4 @@ -* xref:runtime.adoc[Runtime] -* xref:traits.adoc[Traits] -* xref:nrf.adoc[Nordic nRF HAL] -* xref:stm32.adoc[STM32 HAL] +* xref:runtime.adoc[Executor] +* xref:traits.adoc[Async traits] +* xref:hal.adoc[Hardware Interface] +* xref:examples.adoc[Examples] diff --git a/docs/modules/ROOT/pages/examples.adoc b/docs/modules/ROOT/pages/examples.adoc new file mode 100644 index 000000000..198633c77 --- /dev/null +++ b/docs/modules/ROOT/pages/examples.adoc @@ -0,0 +1,3 @@ += Examples + +Embassy provides examples for all HALs supported. You can find them in the `examples/` folder. diff --git a/docs/modules/ROOT/pages/hal.adoc b/docs/modules/ROOT/pages/hal.adoc new file mode 100644 index 000000000..75dd496c9 --- /dev/null +++ b/docs/modules/ROOT/pages/hal.adoc @@ -0,0 +1,9 @@ += Hardware Abstraction Layer (HAL) + +Embassy provides HAL's for several microcontroller families: + +* embassy-nrf for the nRF family of devices from Nordic Semiconductor +* embassy-stm32 for STM32 family of devices from ST Microelectronics +* embassy-rp for Raspberry Pi Pico + +These HALs provide async/await access to most peripherals while also implementing the async traits in Embassy. diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index 5bc35ef43..b795a7238 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -2,23 +2,14 @@ Embassy is a project to make async/await a first-class option for embedded development. -== Traits and types +== What is async? -`embassy` provides a set of traits and types specifically designed for `async` usage. +Software written without async blocks on I/O operations. In a std environment, such as a PC, software handles this problem with threads. When one thread blocks on an I/O operation, another is able to take its place. However, even on a PC, threads are relatively heavy, and therefore some programming languages, such as Go, have implemented a concept called coroutines or 'goroutines' that are much lighter and less-intensive than threads. -* `embassy::io`: `AsyncBufRead`, `AsyncWrite`. Traits for byte-stream IO, essentially `no_std` compatible versions of `futures::io`. -* `embassy::traits::flash`: Flash device trait. -* `embassy::time`: `Clock` and `Alarm` traits. Std-like `Duration` and `Instant`. -* More traits for SPI, I2C, UART async HAL coming soon. +In rust, this concept is implemented as async. async 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. -== Executor +== What is Embassy? -The `embassy::executor` module provides an async/await executor designed for embedded usage. +Embassy is an executor and a Hardware Access Layer (HAL). The executor is a scheduler 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 certain blocking functionality, such as USART, UART, I2C, SPI, CAN, and USB. Embassy doesn't provide access to non-blocking functionality, such as GPIO, because non-blocking functionality doesn't require special treatment to work with Embassy. For such functionality, existing HALs are recommended. -* No `alloc`, no heap needed. Task futures are statically allocated. -* No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning. -* Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`. -* No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`. -* Efficient polling: a wake will only poll the woken task, not all of them. -* Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time. -* Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks. +Embassy also provides a delay trait that can be used to delay a task by a fixed number of microseconds or milliseconds. 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. diff --git a/docs/modules/ROOT/pages/runtime.adoc b/docs/modules/ROOT/pages/runtime.adoc index 2704f298b..8351fd0d1 100644 --- a/docs/modules/ROOT/pages/runtime.adoc +++ b/docs/modules/ROOT/pages/runtime.adoc @@ -1,3 +1,11 @@ = Embassy runtime -TODO +The Embassy excecutor is an async/await executor designed for embedded usage. + +* No `alloc`, no heap needed. Task futures are statically allocated. +* No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning. +* Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`. +* No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`. +* Efficient polling: a wake will only poll the woken task, not all of them. +* Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time. +* Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks. diff --git a/docs/modules/ROOT/pages/stm32.adoc b/docs/modules/ROOT/pages/stm32.adoc deleted file mode 100644 index 328f69e2a..000000000 --- a/docs/modules/ROOT/pages/stm32.adoc +++ /dev/null @@ -1,3 +0,0 @@ -= Embassy STM32 HAL - -TODO diff --git a/docs/modules/ROOT/pages/traits.adoc b/docs/modules/ROOT/pages/traits.adoc index 843cc293e..39e714127 100644 --- a/docs/modules/ROOT/pages/traits.adoc +++ b/docs/modules/ROOT/pages/traits.adoc @@ -1,3 +1,8 @@ = Embassy Traits -TODO +Embassy provides a set of traits and types specifically designed for `async` usage. + +* `embassy::io`: `AsyncBufRead`, `AsyncWrite`. Traits for byte-stream IO, essentially `no_std` compatible versions of `futures::io`. +* `embassy::traits::flash`: Flash device trait. +* `embassy::time`: `Clock` and `Alarm` traits. Std-like `Duration` and `Instant`. +* More traits for SPI, I2C, UART async HAL coming soon. -- cgit From 08e1fcd2e4fa8d5ea000c9870e12b1917ab67e23 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 10 Dec 2021 08:08:56 +0100 Subject: Add example snippet inclusion --- docs/modules/ROOT/examples/examples | 1 + docs/modules/ROOT/pages/examples.adoc | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 120000 docs/modules/ROOT/examples/examples diff --git a/docs/modules/ROOT/examples/examples b/docs/modules/ROOT/examples/examples new file mode 120000 index 000000000..1929330b0 --- /dev/null +++ b/docs/modules/ROOT/examples/examples @@ -0,0 +1 @@ +../../../../examples \ No newline at end of file diff --git a/docs/modules/ROOT/pages/examples.adoc b/docs/modules/ROOT/pages/examples.adoc index 198633c77..c852f5205 100644 --- a/docs/modules/ROOT/pages/examples.adoc +++ b/docs/modules/ROOT/pages/examples.adoc @@ -1,3 +1,11 @@ = Examples Embassy provides examples for all HALs supported. You can find them in the `examples/` folder. + + +Main loop example + +[source,rust] +---- +include::example$examples/std/src/bin/tick.rs[] +---- -- cgit From d2820d5be708d6aa0e6d198809f5913a2cf541bf Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 10 Dec 2021 08:24:39 +0100 Subject: Update section on async --- docs/modules/ROOT/pages/index.adoc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index b795a7238..e4b5aac48 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -4,12 +4,17 @@ Embassy is a project to make async/await a first-class option for embedded devel == What is async? -Software written without async blocks on I/O operations. In a std environment, such as a PC, software handles this problem with threads. When one thread blocks on an I/O operation, another is able to take its place. However, even on a PC, threads are relatively heavy, and therefore some programming languages, such as Go, have implemented a concept called coroutines or 'goroutines' that are much lighter and less-intensive than threads. +Software written without async may block on I/O operations. In an std environment, such as a PC, software can handle this either by using threads or non-blocking operations. -In rust, this concept is implemented as async. async 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. +With threads, one thread blocks on an I/O operation, another is able to take its place. However, even on a PC, threads are relatively heavy, and therefore some programming languages, such as Go, have implemented a concept called coroutines or 'goroutines' that are much lighter and less-intensive than threads. + +The other way to handle blocking I/O operations is to support polling the state of the underlying peripherals to check whether it is available to perform the requested operation. In programming languages without builtin async support, +this requires building a complex loop checking for events. + +In Rust, non-blocking operaetions can be implemented using async-await. 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? -Embassy is an executor and a Hardware Access Layer (HAL). The executor is a scheduler 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 certain blocking functionality, such as USART, UART, I2C, SPI, CAN, and USB. Embassy doesn't provide access to non-blocking functionality, such as GPIO, because non-blocking functionality doesn't require special treatment to work with Embassy. For such functionality, existing HALs are recommended. +Embassy is an executor and a Hardware Access Layer (HAL). The executor is a scheduler 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. -Embassy also provides a delay trait that can be used to delay a task by a fixed number of microseconds or milliseconds. 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. +Embassy 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. -- cgit From 439e317ba30a9a2eec3a3fcc46c88e3f665580e5 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 10 Dec 2021 10:22:11 +0100 Subject: Add diagrams explaining the runtime --- docs/modules/ROOT/images/embassy_executor.drawio | 1 + docs/modules/ROOT/images/embassy_executor.png | Bin 0 -> 121382 bytes docs/modules/ROOT/images/embassy_irq.drawio | 1 + docs/modules/ROOT/images/embassy_irq.png | Bin 0 -> 134158 bytes docs/modules/ROOT/pages/index.adoc | 2 +- docs/modules/ROOT/pages/runtime.adoc | 21 +++++++++++++++++++-- 6 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 docs/modules/ROOT/images/embassy_executor.drawio create mode 100644 docs/modules/ROOT/images/embassy_executor.png create mode 100644 docs/modules/ROOT/images/embassy_irq.drawio create mode 100644 docs/modules/ROOT/images/embassy_irq.png diff --git a/docs/modules/ROOT/images/embassy_executor.drawio b/docs/modules/ROOT/images/embassy_executor.drawio new file mode 100644 index 000000000..b76587d97 --- /dev/null +++ b/docs/modules/ROOT/images/embassy_executor.drawio @@ -0,0 +1 @@ +7Vnhb6IwFP9r+LgFKFX8OJ13u2S3LLcld98uFQo0Q2qgTt1ff2UUsa0IU5y6XLIs9PX1WX7v1997VQOMpsvvKZpFP6mPY8M2/aUBbg3bHjg9/j83rAoDdPuFIUyJX5isyvBE3rAwmsI6Jz7OJEdGaczITDZ6NEmwxyQbSlO6kN0CGsufOkMh1gxPHop162/is6iwutCs7HeYhFH5yZYpZqaodBaGLEI+XWyYwNgAo5RSVjxNlyMc59iVuBTrvtXMrjeW4oS1WfDAsjuIh89/fv8NyGhxv0zMH1dOEeUVxXPxwuMl9uaMpmLTbFUikdJ54uM8mGWA4SIiDD/NkJfPLnjquS1i01hMZy+YeZEYBCSORzTmMfNAIHA97Hm5E0vpC96YmbjQ4ciCodgVThle1r6utQaRkw/TKWbpiruUC3oC95UyXlRptMrcRBspLP2QYE64Dl2Byx8Evh/AGmpYP6PshVus42HtI+wGW7HueS6eBN1g7djnhnVPw1rDGCf+TS4QfOTFKMuIJ8Na5cDsCmTsa2KjQMx3SOeph5uPLENpiFkT3fSUpThGjLzK+9iGv1j6SAnf4TrVoC+nGlhKCov9i1WbcqQEcpoCFS+oBXqnw/p99mdIX2OIdc3HjzRfqlKF5+0eTXhl47TAGXlDk/cpU2YMikmY5HTiOcWcAcP8UBFeS27ExJT4fr5QZpNUwETkqmw0HMx69h+Q+oOOnlsnc/oRvLCSosqc3T+1zNl6/RZgP3QI9hGgA4OTQ/exEpHQJD+4PsqiNYbtikVb6dex28AGboGmtB2o6I6rpKa/r6KrgZzPVXQAWmSUp+FJDDMcTnkKxpVp+LGeQCJDJ/LUSYPgtmwQnJOyzlTIYu7LOqiIMmzHOp5ntNpwm+UOWf2Ge9b2DdftS/Uf7Ha37V3u/KHYb7cHRq8ezroHAjf87xdG/mrrISrbob3aH7WHEtjz4HBowNtdJaeuTWrsiQp1qC1QV+a12Td7Ug6sw5heutAgyPBxFE+/Up6J4n3ulQheguJB2HDhaat4XHpkmqoFuyPFU+u5ZTVIGNzpfyQN09s4W9awR05xkoRfRMVqbvUXrWL6jfFUKtahJrX9msY+qShZqijt2/zbaj9nH0eU1D7JsT9DZAYaQ2GrL4suR1fcJl2xXXjuQlLeN89ASE56AWwrPTU5/38BbNXeKBfA4yiPY2mUBl9LeRzT2KU85jXouRLuV/bpdIgPqx9sC/fqV28w/gc= \ No newline at end of file diff --git a/docs/modules/ROOT/images/embassy_executor.png b/docs/modules/ROOT/images/embassy_executor.png new file mode 100644 index 000000000..2a83a3adb Binary files /dev/null and b/docs/modules/ROOT/images/embassy_executor.png differ diff --git a/docs/modules/ROOT/images/embassy_irq.drawio b/docs/modules/ROOT/images/embassy_irq.drawio new file mode 100644 index 000000000..aa439a8e6 --- /dev/null +++ b/docs/modules/ROOT/images/embassy_irq.drawio @@ -0,0 +1 @@ +5VlNc9owEP01HJOxLdsxx0Bokpk0zZRM0p4ywl6wBmMRWWDIr6+EBf4QKQ6tIbQcPOittLLe7j5J0ELdyeKa4Wn4lQYQtSwjWLTQVcuy2rYrnhJYZoDjXWTAiJEgg8wc6JM3UKCh0BkJICl15JRGnEzLoE/jGHxewjBjNC13G9KoPOsUj0AD+j6OdPSZBDzMUM8xcvwGyChcz2wayjLB684KSEIc0LQAoV4LdRmlPPs2WXQhktytecnGfXnHunkxBjGvM+CeJzcOdB5/PL8MSTe9W8TG7ZmdeZnjaKYW3FuAP+OUqZfmyzUTjM7iAKQzs4U6aUg49KfYl9ZUhF5gIZ9EypyMgfuhagxJFHVpJHxKRyjA4A192YkzOoaCxfU9GAyFRV+bWu4cGIdFAVJrvQY6Ac6Wosva6irel5V2mofRXMcmLIRw3Q+rzBltXOfkii+K3w9w7WhcP+JkfOo829Zn49nVeNY4hji4lOIgWn6Ek4T4ZVrzGBgNkpzQGfNhd3VyzEbAd2cWBCUt00PGIMKczMvSto1/NfSBEvHKm1Cji3KokVkJYbYgNaooRRVH9i5H2Yo1R6t02Kxn/wy50DLEPG/JHHUjQXNnIMTPHfFV6DIkIPM19ECl/wwWkxcsepaJeNzhgdgQRUZBQt7wYGUyysmGIzKKZSaK/ACRPB1ZfERsQZfKMCFBIAeWE1FPq99Vg9of1Rvku1KNQq+dNX9UtZa+Fd1KPthsKjPnBseCgwZ3paHng7+1kAeeYztGM7sS8g6oli9P8/YrfvVf3O8/A3Y9f5oTdGZqtDeolrVJrkjZfvJp1dVPuxG5tNrlWIvD7znybNd01NPdUz1Rxa9nn+dOxdNuSky3JpClJZBTW0zvKSfD5SeS09oyWc7I9yvrAHK6dXL0f5X1Vg6cZsq6Un6ovecpCFX0wW7uFLSVHn3DtWXhPuMxnHztoWPWnn7RewBGpiEwLMf2OeY6wwc4yFy2u3avIywjhgMiCCyOWn2Ut756rRD74YxBYcQVYSJEhMpYppDkOr0jSB+7Qx7/VPQ575B/RT6do6qnXRE9ZO2pnm5VhquOGlZP/Q5p1T72XKaYyKXcipm//aOnH/eYCuyd7Oln513FauiyUpFgx9izLqvHo037QHXZ1kKPZF0Wfks48cLymiks0cz/i8iCkf+hg3q/AA== \ No newline at end of file diff --git a/docs/modules/ROOT/images/embassy_irq.png b/docs/modules/ROOT/images/embassy_irq.png new file mode 100644 index 000000000..154d336b6 Binary files /dev/null and b/docs/modules/ROOT/images/embassy_irq.png differ diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index e4b5aac48..9a14e465d 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -11,7 +11,7 @@ With threads, one thread blocks on an I/O operation, another is able to take its The other way to handle blocking I/O operations is to support polling the state of the underlying peripherals to check whether it is available to perform the requested operation. In programming languages without builtin async support, this requires building a complex loop checking for events. -In Rust, non-blocking operaetions can be implemented using async-await. 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. +In Rust, non-blocking operations can be implemented using async-await. 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? diff --git a/docs/modules/ROOT/pages/runtime.adoc b/docs/modules/ROOT/pages/runtime.adoc index 8351fd0d1..39cf2545e 100644 --- a/docs/modules/ROOT/pages/runtime.adoc +++ b/docs/modules/ROOT/pages/runtime.adoc @@ -1,11 +1,28 @@ = Embassy runtime -The Embassy excecutor is an async/await executor designed for embedded usage. +The Embassy executor is an async/await executor designed for embedded usage. -* No `alloc`, no heap needed. Task futures are statically allocated. +* No `alloc`, no heap needed. Task are statically allocated. * No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning. * Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`. * No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`. * Efficient polling: a wake will only poll the woken task, not all of them. * Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time. * Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks. + +== Executor + +The executor function is described below. The executor keeps a queue of tasks that it should poll. When a task is created, it is polled (1). The task will attempt to make progress until reaches a point where it would be blocked. This may happen whenever a task is .await'ing an async function. When that happens, the task yields execution by (2) returning `Poll::Pending`. Once a task yields, the executor enqueues the task at the end of the run queue, and proceeds to (3) poll the next task in the queue. If a task returns `Poll::Ready` it essentially means that the task is finished and will not be enqueued again. + +IMPORTANT: The executor relies on tasks not blocking indefinitely, as this prevents the executor to regain control and schedule another task. + +image::embassy_executor.png[Executor model] + + +== Interrupts + +Interrupts are a common way for peripherals to signal completion of some operation and fits well with the async execution model. The following diagram describes a typical application flow where (1) a task is polled and is attempting to make progress. The task then (2) instructs the peripheral to perform some operation, and awaits. After some time has passede, (3) an interrupt is raised, marking the completion of the operation. + +The peripheral HAL then (4) ensures that interrupt signals are routed to to the peripheral and updating the peripheral state with the results of the operation. The executor is then (5) notified that the task should be polled, which it will do. + +image::embassy_irq.png[Interrupt handling] -- cgit From 7568d0bb68b5d37adf6229ac57c0c961a2a9e803 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 10 Dec 2021 10:47:34 +0100 Subject: More on traits and notes on time --- docs/modules/ROOT/pages/runtime.adoc | 12 +++++++++++- docs/modules/ROOT/pages/traits.adoc | 11 ++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/docs/modules/ROOT/pages/runtime.adoc b/docs/modules/ROOT/pages/runtime.adoc index 39cf2545e..2970bd59e 100644 --- a/docs/modules/ROOT/pages/runtime.adoc +++ b/docs/modules/ROOT/pages/runtime.adoc @@ -1,6 +1,8 @@ = Embassy runtime -The Embassy executor is an async/await executor designed for embedded usage. +The Embassy runtime is an async/await executor designed for embedded usage along with support functionality for interrupts and timers. + +== Features * No `alloc`, no heap needed. Task are statically allocated. * No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning. @@ -26,3 +28,11 @@ Interrupts are a common way for peripherals to signal completion of some operati The peripheral HAL then (4) ensures that interrupt signals are routed to to the peripheral and updating the peripheral state with the results of the operation. The executor is then (5) notified that the task should be polled, which it will do. image::embassy_irq.png[Interrupt handling] + +== Time + +Embassy features an internal timer queue enabled by the `time` feature flag. When enabled, Embassy assumes a time `Driver` implementation existing for the platform. Embassy provides time drivers for the nRF, STM32, RPi Pico, WASM and Std platforms. + +The timer driver implementations for the embedded platforms support a fixed number of alarms that can be set, which is normally the number of tasks you expect wanting to use the timer at the same time. + +NOTE: If you do not require timers in your application, not enabling the `time` feature can save some CPU cycles and reduce power usage. diff --git a/docs/modules/ROOT/pages/traits.adoc b/docs/modules/ROOT/pages/traits.adoc index 39e714127..96f3e88bb 100644 --- a/docs/modules/ROOT/pages/traits.adoc +++ b/docs/modules/ROOT/pages/traits.adoc @@ -1,8 +1,9 @@ = Embassy Traits -Embassy provides a set of traits and types specifically designed for `async` usage. +Embassy provides a set of traits and types specifically designed for `async` usage. Many of these futures will be upstreamed to the `embedded-hal` crate at some point in the future, probably when the required GAT (Generic Associated Types) feature is stabilized in Rust. -* `embassy::io`: `AsyncBufRead`, `AsyncWrite`. Traits for byte-stream IO, essentially `no_std` compatible versions of `futures::io`. -* `embassy::traits::flash`: Flash device trait. -* `embassy::time`: `Clock` and `Alarm` traits. Std-like `Duration` and `Instant`. -* More traits for SPI, I2C, UART async HAL coming soon. +* `embassy::io`: `AsyncBufRead`, `AsyncWrite`. Traits for byte-stream IO, essentially `no_std` compatible versions of `futures::io`. The primary reason for re-defining these traits is that the `futures::io` variant requires `std::io::Error`, which does not work in the `no_std` environment. +* `embassy::traits`: Async traits for Flash, SPI, I2C, UART, RNG, GPIO and more. +* `embassy::time`: Time `Driver` trait that is implemented for different platforms. Time in Embassy is represented using the `Duration` and `Instant` types. + +These traits are implemented by the platform-specific crates, such as `embassy-nrf` or `embassy-stm32`. -- cgit From b48fcd9229b40800cc96ff3157d8b36057dc2047 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 10 Dec 2021 12:04:12 +0100 Subject: Add more content --- docs/modules/ROOT/nav.adoc | 10 ++-- docs/modules/ROOT/pages/basic_application.adoc | 75 ++++++++++++++++++++++++++ docs/modules/ROOT/pages/getting_started.adoc | 59 ++++++++++++++++++++ docs/modules/ROOT/pages/hal.adoc | 8 +-- docs/modules/ROOT/pages/nrf.adoc | 24 ++++++++- docs/modules/ROOT/pages/runtime.adoc | 10 +++- docs/modules/ROOT/pages/stm32.adoc | 3 ++ 7 files changed, 180 insertions(+), 9 deletions(-) create mode 100644 docs/modules/ROOT/pages/basic_application.adoc create mode 100644 docs/modules/ROOT/pages/getting_started.adoc create mode 100644 docs/modules/ROOT/pages/stm32.adoc diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index dbf9b0bae..98c4ee77f 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -1,4 +1,8 @@ -* xref:runtime.adoc[Executor] -* xref:traits.adoc[Async traits] -* xref:hal.adoc[Hardware Interface] +* xref:runtime.adoc[Runtime] +* xref:traits.adoc[APIs] +* xref:hal.adoc[Hardware Abstraction Layer] +** xref:nrf.adoc[nRF] +** xref:stm32.adoc[STM32] +* xref:getting_started.adoc[Getting started] +** xref:basic_application.adoc[Basic application] * xref:examples.adoc[Examples] 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 @@ += A basic Embassy application + +So 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. + + +== The Cargo.toml + +== The main + +=== Rust Nightly + +The first thing you'll notice is a few declarations stating that Embassy requires some nightly features: + +[source,rust] +---- +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] +---- + +=== Dealing with errors + +Then, 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: + +[source,rust] +---- +use defmt_rtt as _; +use panic_probe as _; +---- + +=== Task declaration + +After a bit of import declaration, the tasks run by the application should be declared: + +[source,rust] +---- +#[embassy::task] +async fn blinker(led: Output<'static, P0_13>, interval: Duration) { + loop { + let _ = led.set_high(); + Timer::after(interval).await; + let _ = led.set_low(); + Timer::after(interval).await; + } +} +---- + +An 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. + +NOTE: 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. + +=== Main + +The 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. + +The `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: + +[source, rust] +---- +#[embassy::main] +async fn main(spawner: Spawner, p: Peripherals) { + let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); + let _ = spawner.spawn(blinker(led, Duration::from_millis(300))); +} +---- + + +What 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: + +. Creates an Embassy Executor instance +. Initializes the microcontroller to get the `Peripherals` +. Defines a main task for the entry point +. Runs the executor spawning the main task + +There is also a way to run the executor without using the macro, in which case you have to create the `Executor` instance yourself. diff --git a/docs/modules/ROOT/pages/getting_started.adoc b/docs/modules/ROOT/pages/getting_started.adoc new file mode 100644 index 000000000..760fe8601 --- /dev/null +++ b/docs/modules/ROOT/pages/getting_started.adoc @@ -0,0 +1,59 @@ += Getting started + +So you want to try Embassy, great! To get started, there are a few tools you need to install: + +* link:https://rustup.rs/[rustup] - the Rust toolchain is needed to compile Rust code. +* link:https://crates.io/crates/probe-run[probe-run] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well. + +If you don't have any supported board, don't worry: you can also run embassy on your PC using the `std` examples. + +== 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. + +=== nRF kits + +* link:https://www.nordicsemi.com/Products/Development-hardware/nrf52-dk[nRF52 DK] +* link:https://www.nordicsemi.com/Products/Development-hardware/nRF9160-DK[nRF9160 DK] + +=== STM32 kits + +* link:https://www.st.com/en/evaluation-tools/nucleo-h743zi.html[STM32 Nucleo-144 development board with STM32H743ZI MCU] +* link:https://www.st.com/en/evaluation-tools/nucleo-f429zi.html[STM32 Nucleo-144 development board with STM32F429ZI MCU] +* link:https://www.st.com/en/evaluation-tools/b-l4s5i-iot01a.html[STM32L4+ Discovery kit IoT node, low-power wireless, BLE, NFC, WiFi] +* link:https://www.st.com/en/evaluation-tools/b-l072z-lrwan1.html[STM32L0 Discovery kit LoRa, Sigfox, low-power wireless] +* link:https://www.st.com/en/evaluation-tools/nucleo-wl55jc.html[STM32 Nucleo-64 development board with STM32WL55JCI MCU] +* link:https://www.st.com/en/evaluation-tools/b-u585i-iot02a.html[Discovery kit for IoT node with STM32U5 series] + + +=== RP2040 kits + +* link:https://www.raspberrypi.com/products/raspberry-pi-pico/[Raspberry Pi Pico] + +== Running an example + +First you need to clone the [github repository]; + +[source, bash] +---- +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: + +[source, bash] +---- +cd examples/nrf +DEFMT_LOG=info cargo run --bin blinky --release +---- + +IMPORTANT: The DEFMT_LOG environment variable controls the example log verbosity. If you do not specify it, you will not see anything logged to the console. + +== Whats next? + +Congratulations, you have your first Embassy application running! Here are some alternatives on where to go from here: + +* Read more about the xref:runtime.adoc[runtime]. +* Read more about the xref:hal.adoc[HAL]. +* Start xref:basic_application.adoc[writing your application]. diff --git a/docs/modules/ROOT/pages/hal.adoc b/docs/modules/ROOT/pages/hal.adoc index 75dd496c9..8e7fb8dba 100644 --- a/docs/modules/ROOT/pages/hal.adoc +++ b/docs/modules/ROOT/pages/hal.adoc @@ -2,8 +2,8 @@ Embassy provides HAL's for several microcontroller families: -* embassy-nrf for the nRF family of devices from Nordic Semiconductor -* embassy-stm32 for STM32 family of devices from ST Microelectronics -* embassy-rp for Raspberry Pi Pico +* `embassy-nrf` for the nRF microcontroller sfrom Nordic Semiconductor +* `embassy-stm32` for STM32 microcontrollers from ST Microelectronics +* `embassy-rp` for the Raspberry Pi RP2040 microcontrollers -These HALs provide async/await access to most peripherals while also implementing the async traits in Embassy. +These HALs implement async/await functionality for most peripherals while also implementing the async traits in Embassy. diff --git a/docs/modules/ROOT/pages/nrf.adoc b/docs/modules/ROOT/pages/nrf.adoc index 21c388f61..10fe54b47 100644 --- a/docs/modules/ROOT/pages/nrf.adoc +++ b/docs/modules/ROOT/pages/nrf.adoc @@ -1,3 +1,25 @@ = Embassy nRF HAL -TODO +The link:https://github.com/embassy-rs/embassy/tree/master/embassy-nrf[Embassy nRF HAL] is based on the PACs (Peripheral Access Crate) from link:https://github.com/nrf-rs/[nrf-rs]. + +== Timer driver + +The nRF timer driver operates at 32768 Hz by default. + +== Peripherals + +The following peripherals have a HAL implementation at present: + +* PWM +* SPIM +* QSPI +* NVMC +* GPIOTE +* RNG +* TIMER +* WDT +* TEMP +* PPI +* UARTE +* TWIM +* SAADC diff --git a/docs/modules/ROOT/pages/runtime.adoc b/docs/modules/ROOT/pages/runtime.adoc index 2970bd59e..25feb9c29 100644 --- a/docs/modules/ROOT/pages/runtime.adoc +++ b/docs/modules/ROOT/pages/runtime.adoc @@ -20,6 +20,8 @@ IMPORTANT: The executor relies on tasks not blocking indefinitely, as this preve image::embassy_executor.png[Executor model] +If you use the `#[embassy::main]` macro in your application, it creates the `Executor` for you and spawns the main entry point as the first task. You can also create the Executor manually, and you can in fact create multiple Executors. + == Interrupts @@ -29,10 +31,16 @@ The peripheral HAL then (4) ensures that interrupt signals are routed to to the image::embassy_irq.png[Interrupt handling] +NOTE: There exists a special executor named `InterruptExecutor` which can be driven by an interrupt. This can be used to drive tasks at different priority levels by creating multiple `InterruptExecutor` instances. + == Time Embassy features an internal timer queue enabled by the `time` feature flag. When enabled, Embassy assumes a time `Driver` implementation existing for the platform. Embassy provides time drivers for the nRF, STM32, RPi Pico, WASM and Std platforms. -The timer driver implementations for the embedded platforms support a fixed number of alarms that can be set, which is normally the number of tasks you expect wanting to use the timer at the same time. +The timer driver implementations for the embedded platforms might support only a fixed number of alarms that can be set. Make sure the number of tasks you expect wanting to use the timer at the same time do not exceed this limit. + +The timer speed is configurable at compile time using the `time-tick-`. At present, the the timer may be configured to run at 1000 Hz, 32768 Hz, or 1 MHz. Before changing the defaults, make sure the target HAL supports the particular frequency setting. + + NOTE: If you do not require timers in your application, not enabling the `time` feature can save some CPU cycles and reduce power usage. diff --git a/docs/modules/ROOT/pages/stm32.adoc b/docs/modules/ROOT/pages/stm32.adoc new file mode 100644 index 000000000..328f69e2a --- /dev/null +++ b/docs/modules/ROOT/pages/stm32.adoc @@ -0,0 +1,3 @@ += Embassy STM32 HAL + +TODO -- cgit From e93f2679b1edbedd83e09fbc3b7a07dbf1ef80a4 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 10 Dec 2021 12:27:44 +0100 Subject: More content --- docs/modules/ROOT/pages/basic_application.adoc | 15 +++++++++++++-- docs/modules/ROOT/pages/stm32.adoc | 23 ++++++++++++++++++++++- examples/nrf/src/bin/blinky.rs | 19 +++++++++++-------- 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/docs/modules/ROOT/pages/basic_application.adoc b/docs/modules/ROOT/pages/basic_application.adoc index d56cb5e1d..53aaa3d7d 100644 --- a/docs/modules/ROOT/pages/basic_application.adoc +++ b/docs/modules/ROOT/pages/basic_application.adoc @@ -3,8 +3,6 @@ So 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. -== The Cargo.toml - == The main === Rust Nightly @@ -73,3 +71,16 @@ What happens when the `blinker` task have been spawned and main returns? Well, t . Runs the executor spawning the main task There is also a way to run the executor without using the macro, in which case you have to create the `Executor` instance yourself. + +== The Cargo.toml + +The project definition needs to contain the embassy dependencies: + +[source,toml] +---- +include::example$examples/nrf/Cargo.toml[lines="9..11"] +---- + +Depending on your microcontroller, you may need to replace `embassy-nrf` with something else (`embassy-stm32` for STM32. Remember to update feature flags as well). + +In this particular case, the nrf52840 chip is selected, and the RTC1 peripheral is used as the time driver. diff --git a/docs/modules/ROOT/pages/stm32.adoc b/docs/modules/ROOT/pages/stm32.adoc index 328f69e2a..3d1fbfc8f 100644 --- a/docs/modules/ROOT/pages/stm32.adoc +++ b/docs/modules/ROOT/pages/stm32.adoc @@ -1,3 +1,24 @@ = Embassy STM32 HAL -TODO +The link:https://github.com/embassy-rs/embassy/tree/master/embassy-stm32[Embassy STM32 HAL] is based on the `stm32-metapac` project. + +== The infinite variant problem + +STM32 microcontrollers comes in many families and flavors, and supporting all of them is a big undertaking. Embassy has taken advantage of the fact +that the STM32 peripheral versions are shared across chip families. Instead of re-implementing the SPI +peripheral for every STM32 chip family, embassy have a single SPI implementation that depends on +code-generated register types that are identical for STM32 families with the same version of a given peripheral. + +=== The metapac + +The `stm32-metapac` module uses pre-generated chip and register definitions for STM32 chip families to generate register types. This is done at compile time based on Cargo feataure flags. + +The chip and register definitions are located in a separate module, `stm32-data`, which is modified whenever a bug is found in the definitions, or when adding support for new chip families. + +=== The HAL + +The `embassy-stm32` module contains the HAL implementation for all STM32 families. The implementation uses automatically derived feature flags to support the correct version of a given peripheral for a given chip family. + +== Timer driver + +The STM32 timer driver operates at 32768 Hz by default. diff --git a/examples/nrf/src/bin/blinky.rs b/examples/nrf/src/bin/blinky.rs index a12fe58ff..3a1440684 100644 --- a/examples/nrf/src/bin/blinky.rs +++ b/examples/nrf/src/bin/blinky.rs @@ -8,18 +8,21 @@ mod example_common; use defmt::unwrap; use embassy::executor::Spawner; use embassy::time::{Duration, Timer}; -use embassy_nrf::gpio::{Level, Output, OutputDrive}; -use embassy_nrf::Peripherals; +use embassy_nrf::{Peripherals, peripherals::P0_13, gpio::{Level, Output, OutputDrive}; use embedded_hal::digital::v2::OutputPin; -#[embassy::main] -async fn main(_spawner: Spawner, p: Peripherals) { - let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); - +#[embassh::task] +async fn blinker(led: Output<'static, P0_13>, interval: Duration) { loop { unwrap!(led.set_high()); - Timer::after(Duration::from_millis(300)).await; + Timer::after(interval).await; unwrap!(led.set_low()); - Timer::after(Duration::from_millis(300)).await; + Timer::after(interval).await; } } + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); + unwrap!(spawner.spawn(blinker(led, Duration::from_millis(300)))); +} -- cgit From 9b01eed1956421dd7c0ad644f77e14a05ab92923 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 10 Dec 2021 12:32:20 +0100 Subject: Revert blinky changes for now --- examples/nrf/src/bin/blinky.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/examples/nrf/src/bin/blinky.rs b/examples/nrf/src/bin/blinky.rs index 3a1440684..a12fe58ff 100644 --- a/examples/nrf/src/bin/blinky.rs +++ b/examples/nrf/src/bin/blinky.rs @@ -8,21 +8,18 @@ mod example_common; use defmt::unwrap; use embassy::executor::Spawner; use embassy::time::{Duration, Timer}; -use embassy_nrf::{Peripherals, peripherals::P0_13, gpio::{Level, Output, OutputDrive}; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::Peripherals; use embedded_hal::digital::v2::OutputPin; -#[embassh::task] -async fn blinker(led: Output<'static, P0_13>, interval: Duration) { +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); + loop { unwrap!(led.set_high()); - Timer::after(interval).await; + Timer::after(Duration::from_millis(300)).await; unwrap!(led.set_low()); - Timer::after(interval).await; + Timer::after(Duration::from_millis(300)).await; } } - -#[embassy::main] -async fn main(_spawner: Spawner, p: Peripherals) { - let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); - unwrap!(spawner.spawn(blinker(led, Duration::from_millis(300)))); -} -- cgit From e5d4d0952b78ef343f14205f5ebd3f1d7804f9e8 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 10 Dec 2021 12:46:41 +0100 Subject: Add doc-specific example and add it to CI --- ci.sh | 1 + .../modules/ROOT/examples/basic/.cargo/config.toml | 6 +++++ docs/modules/ROOT/examples/basic/Cargo.toml | 18 +++++++++++++ docs/modules/ROOT/examples/basic/src/main.rs | 30 ++++++++++++++++++++++ docs/modules/ROOT/pages/basic_application.adoc | 30 ++++++---------------- 5 files changed, 63 insertions(+), 22 deletions(-) create mode 100644 docs/modules/ROOT/examples/basic/.cargo/config.toml create mode 100644 docs/modules/ROOT/examples/basic/Cargo.toml create mode 100644 docs/modules/ROOT/examples/basic/src/main.rs diff --git a/ci.sh b/ci.sh index 6beea8677..ec610d7f6 100755 --- a/ci.sh +++ b/ci.sh @@ -40,6 +40,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt \ + --- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi --- build --release --manifest-path examples/std/Cargo.toml --target x86_64-unknown-linux-gnu --out-dir out/examples/std \ --- build --release --manifest-path examples/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf \ --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ diff --git a/docs/modules/ROOT/examples/basic/.cargo/config.toml b/docs/modules/ROOT/examples/basic/.cargo/config.toml new file mode 100644 index 000000000..c75b5c539 --- /dev/null +++ b/docs/modules/ROOT/examples/basic/.cargo/config.toml @@ -0,0 +1,6 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips` +runner = "probe-run --chip nRF52840_xxAA" + +[build] +target = "thumbv7em-none-eabi" diff --git a/docs/modules/ROOT/examples/basic/Cargo.toml b/docs/modules/ROOT/examples/basic/Cargo.toml new file mode 100644 index 000000000..a683a28bf --- /dev/null +++ b/docs/modules/ROOT/examples/basic/Cargo.toml @@ -0,0 +1,18 @@ +[package] +authors = ["Dario Nieuwenhuis "] +edition = "2018" +name = "embassy-basic-example" +version = "0.1.0" + +[dependencies] +embassy = { version = "0.1.0", path = "../../../../embassy", features = ["defmt"] } +embassy-traits = { version = "0.1.0", path = "../../../../embassy-traits", features = ["defmt"] } +embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } + +defmt = "0.3" +defmt-rtt = "0.3" + +cortex-m = "0.7.3" +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +panic-probe = { version = "0.3", features = ["print-defmt"] } diff --git a/docs/modules/ROOT/examples/basic/src/main.rs b/docs/modules/ROOT/examples/basic/src/main.rs new file mode 100644 index 000000000..0152b40bb --- /dev/null +++ b/docs/modules/ROOT/examples/basic/src/main.rs @@ -0,0 +1,30 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt_rtt as _; // global logger +use panic_probe as _; + +use defmt::*; + +use embassy::executor::Spawner; +use embassy::time::{Duration, Timer}; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::Peripherals; +use embedded_hal::digital::v2::OutputPin; + +#[embassy::task] +async fn blinker(mut led: Output<'static, P0_13>, interval: Duration) { + loop { + unwrap!(led.set_high()); + Timer::after(interval).await; + unwrap!(led.set_low()); + Timer::after(interval).await; + } +} + +#[embassy::main] +async fn main(spawner: Spawner, p: Peripherals) { + let led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); + unwrap!(spawner.spawn(blinker(led, Duration::from_millis(300)))); +} diff --git a/docs/modules/ROOT/pages/basic_application.adoc b/docs/modules/ROOT/pages/basic_application.adoc index 53aaa3d7d..c2849927a 100644 --- a/docs/modules/ROOT/pages/basic_application.adoc +++ b/docs/modules/ROOT/pages/basic_application.adoc @@ -2,8 +2,9 @@ So 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. +== Main -== The main +The full example can be found link:https://github.com/embassy-rs/embassy/tree/book-poc/docs/modules/ROOT/examples/basic[here]. === Rust Nightly @@ -11,9 +12,7 @@ The first thing you'll notice is a few declarations stating that Embassy require [source,rust] ---- -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] +include::example$basic/src/main.rs[lines="1..3"] ---- === Dealing with errors @@ -22,8 +21,7 @@ Then, what follows are some declarations on how to deal with panics and faults. [source,rust] ---- -use defmt_rtt as _; -use panic_probe as _; +include::example$basic/src/main.rs[lines="5..6"] ---- === Task declaration @@ -32,15 +30,7 @@ After a bit of import declaration, the tasks run by the application should be de [source,rust] ---- -#[embassy::task] -async fn blinker(led: Output<'static, P0_13>, interval: Duration) { - loop { - let _ = led.set_high(); - Timer::after(interval).await; - let _ = led.set_low(); - Timer::after(interval).await; - } -} +include::example$basic/src/main.rs[lines="16..24"] ---- An 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. @@ -53,13 +43,9 @@ The main entry point of an Embassy application is defined using the `#[embassy:: The `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: -[source, rust] +[source,rust] ---- -#[embassy::main] -async fn main(spawner: Spawner, p: Peripherals) { - let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); - let _ = spawner.spawn(blinker(led, Duration::from_millis(300))); -} +include::example$basic/src/main.rs[lines="26..30"] ---- @@ -78,7 +64,7 @@ The project definition needs to contain the embassy dependencies: [source,toml] ---- -include::example$examples/nrf/Cargo.toml[lines="9..11"] +include::example$basic/Cargo.toml[lines="8..10"] ---- Depending on your microcontroller, you may need to replace `embassy-nrf` with something else (`embassy-stm32` for STM32. Remember to update feature flags as well). -- cgit From aa0abe976a481b0fb58d6bdee5d448658e6f8ffc Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 10 Dec 2021 12:58:23 +0100 Subject: Fix doc example compile --- docs/modules/ROOT/examples/basic/Cargo.toml | 5 ++--- docs/modules/ROOT/examples/basic/src/main.rs | 7 +++++-- docs/modules/ROOT/pages/basic_application.adoc | 6 +++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/modules/ROOT/examples/basic/Cargo.toml b/docs/modules/ROOT/examples/basic/Cargo.toml index a683a28bf..0f1c30da3 100644 --- a/docs/modules/ROOT/examples/basic/Cargo.toml +++ b/docs/modules/ROOT/examples/basic/Cargo.toml @@ -5,9 +5,8 @@ name = "embassy-basic-example" version = "0.1.0" [dependencies] -embassy = { version = "0.1.0", path = "../../../../embassy", features = ["defmt"] } -embassy-traits = { version = "0.1.0", path = "../../../../embassy-traits", features = ["defmt"] } -embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } +embassy = { version = "0.1.0", path = "../../../../../embassy", features = ["defmt"] } +embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } defmt = "0.3" defmt-rtt = "0.3" diff --git a/docs/modules/ROOT/examples/basic/src/main.rs b/docs/modules/ROOT/examples/basic/src/main.rs index 0152b40bb..2a9b1facc 100644 --- a/docs/modules/ROOT/examples/basic/src/main.rs +++ b/docs/modules/ROOT/examples/basic/src/main.rs @@ -9,8 +9,11 @@ use defmt::*; use embassy::executor::Spawner; use embassy::time::{Duration, Timer}; -use embassy_nrf::gpio::{Level, Output, OutputDrive}; -use embassy_nrf::Peripherals; +use embassy_nrf::{ + gpio::{Level, Output, OutputDrive}, + peripherals::P0_13, + Peripherals, +}; use embedded_hal::digital::v2::OutputPin; #[embassy::task] diff --git a/docs/modules/ROOT/pages/basic_application.adoc b/docs/modules/ROOT/pages/basic_application.adoc index c2849927a..46a375c86 100644 --- a/docs/modules/ROOT/pages/basic_application.adoc +++ b/docs/modules/ROOT/pages/basic_application.adoc @@ -30,7 +30,7 @@ After a bit of import declaration, the tasks run by the application should be de [source,rust] ---- -include::example$basic/src/main.rs[lines="16..24"] +include::example$basic/src/main.rs[lines="18..27"] ---- An 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. @@ -45,7 +45,7 @@ The `Spawner` is the way the main application spawns other tasks. The `Periphera [source,rust] ---- -include::example$basic/src/main.rs[lines="26..30"] +include::example$basic/src/main.rs[lines="28..-1"] ---- @@ -64,7 +64,7 @@ The project definition needs to contain the embassy dependencies: [source,toml] ---- -include::example$basic/Cargo.toml[lines="8..10"] +include::example$basic/Cargo.toml[lines="8..9"] ---- Depending on your microcontroller, you may need to replace `embassy-nrf` with something else (`embassy-stm32` for STM32. Remember to update feature flags as well). -- cgit From ff82c76935d86b7444e6abc7296c4c3e09261484 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 10 Dec 2021 13:10:02 +0100 Subject: Fix broken ci.sh --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index ec610d7f6..28c06823f 100755 --- a/ci.sh +++ b/ci.sh @@ -40,7 +40,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt \ - --- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi + --- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path examples/std/Cargo.toml --target x86_64-unknown-linux-gnu --out-dir out/examples/std \ --- build --release --manifest-path examples/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf \ --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ -- cgit