Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to esp-generate #172

Merged
merged 1 commit into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ additional-js = ["assets/mermaid.min.js", "assets/mermaid-init.js"]
"/overview/bare-metal.html" = "https://esp-rs.github.io/book/overview/using-the-core-library.html"
"/tooling/text-editors-and-ides.html" = "https://esp-rs.github.io/book/tooling/visual-studio-code.html"
"/debugging/vscode-debugging.html" = "https://esp-rs.github.io/book/debugging/vscode.html"
"/writing-your-own-application/no-std-applications/understanding-esp-template.html" = "https://esp-rs.github.io/book/writing-your-own-application/generate-project/esp-template.html"
"/writing-your-own-application/no-std-applications/understanding-esp-template.html" = "https://esp-rs.github.io/book/writing-your-own-application/generate-project/esp-generate.html"
"installation/installation.html" = "https://esp-rs.github.io/book/installation/index.html"
"troubleshooting/espflash.html" = "https://esp-rs.github.io/book/troubleshooting/index.html"

Expand Down
2 changes: 1 addition & 1 deletion src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
- [Using Containers](./installation/using-containers.md)
- [Writing Your Own Application](./writing-your-own-application/index.md)
- [Generating Projects from Templates](./writing-your-own-application/generate-project/index.md)
- [Understanding `esp-template`](./writing-your-own-application/generate-project/esp-template.md)
- [Understanding `esp-generate`](./writing-your-own-application/generate-project/esp-generate.md)
- [Understanding `esp-idf-template`](./writing-your-own-application/generate-project/esp-idf-template.md)
- [Writing `no_std` Applications](./writing-your-own-application/nostd.md)
- [Writing `std` Applications](./writing-your-own-application/std.md)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Understanding `esp-template`
# Understanding `esp-generate`

Now that we know how to [generate a `no_std` project][generate-no-std], let's inspect what the generated
project contains, try to understand every part of it, and run it.
Expand All @@ -7,48 +7,52 @@ project contains, try to understand every part of it, and run it.

## Inspecting the Generated Project

When creating a project from [`esp-template`][esp-template] with the following answers:
- Which MCU to target? · `esp32c3`
- Configure advanced template options? · `false`

For this explanation, we will use the default values, if you want further modifications, see the [additional prompts][prompts] when not using default values.
When creating a project from [`esp-generate`][esp-generate] with no extra options:
```
esp-generate --chip esp32c3 your-project
```

It should generate a file structure like this:

```text
├── build.rs
├── .cargo
│   └── config.toml
├── src
│   └── main.rs
├── .gitignore
│ └── config.toml
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
└── rust-toolchain.toml
├── .gitignore
├── rust-toolchain.toml
├── src
│ ├── bin
│ │ └── main.rs
│ └── lib.rs
└── .vscode
└── settings.json
```

Before going further, let's see what these files are for.

- [`build.rs`][build.rs]
- Sets the linker script arguments based on the template options.
- [`.cargo/config.toml`][config-toml]
- The Cargo configuration
- This defines a few options to correctly build the project
- Contains `runner = "espflash flash --monitor"` - this means you can just use `cargo run` to flash and monitor your code
- `src/main.rs`
- The main source file of the newly created project
- For details, see the [Understanding `main.rs`][main-rs] section below
- [`.gitignore`][gitignore]
- Tells `git` which folders and files to ignore
- Contains the custom runner command for `espflash` or `probe-rs`. For example, `runner = "espflash flash --monitor"` - this means you can just use `cargo run` to flash and monitor your code
- [`Cargo.toml`][cargo-toml]
- The usual Cargo manifest declares some meta-data and dependencies of the project
- `LICENSE-APACHE`, `LICENSE_MIT`
- Those are the most common licenses used in the Rust ecosystem
- If you want to use a different license, you can delete these files and change the license in `Cargo.toml`
- [`.gitignore`][gitignore]
- Tells `git` which folders and files to ignore
- [`rust-toolchain.toml`][rust-toolchain-toml]
- Defines which Rust toolchain to use
- The toolchain will be `nightly` or `esp` depending on your target
- `src/bin/main.rs`
- The main source file of the newly created project
- For details, see the [Understanding `main.rs`][main-rs] section below
- `src/lib.rs`
- This tells the Rust compiler that this code doesn't use `libstd`
- `.vscode/settings.json`
- Defines a set of settings for Visual Studio Code to make Rust Analyzer work.

[esp-template]: https://github.com/esp-rs/esp-template
[prompts]: https://github.com/esp-rs/esp-template#esp-template
[esp-generate]: https://github.com/esp-rs/esp-generate
[build.rs]: https://doc.rust-lang.org/cargo/reference/build-scripts.html
[main-rs]: #understanding-mainrs
[cargo-toml]: https://doc.rust-lang.org/cargo/reference/manifest.html
[gitignore]: https://git-scm.com/docs/gitignore
Expand All @@ -68,44 +72,43 @@ Before going further, let's see what these files are for.
- The `no_main` attribute says that this program won't use the standard main interface, which is usually used when a full operating system is available. Instead of the standard main, we'll use the entry attribute from the `esp-riscv-rt` crate to define a custom entry point. In this program, we have named the entry point `main`, but any other name could have been used. The entry point function must be a [diverging function][diverging-function]. I.e. it has the signature `fn foo() -> !`; this type indicates that the function never returns – which means that the program never terminates.

```rust,ignore
4 use esp_backtrace as _;
5 use esp_println::println;
6 use esp_hal::{clock::ClockControl, peripherals::Peripherals, prelude::*, timer::TimerGroup, Rtc};
4 use esp_backtrace as _;
5 use esp_hal::delay::Delay;
6 use esp_hal::prelude::*;
7 use log::info;
```
- `use esp_backtrace as _;`
- Since we are in a bare-metal environment, we need a panic handler that runs if a panic occurs in code
- There are a few different crates you can use (e.g `panic-halt`) but `esp-backtrace` provides an implementation that prints the address of a backtrace - together with `espflash` these addresses can get decoded into source code locations
- `use esp_println::println;`
- Provides `println!` implementation
- `use esp_hal::{...}`
- We need to bring in some types we are going to use
- `use esp_hal::delay::Delay;`
- Provides `Delay` driver implementation.
- `use esp_hal::prelude::*;`
- Imports the `esp-hal` [prelude][prelude].

```rust,ignore
8 #[entry]
9 fn main() -> ! {
10 let peripherals = Peripherals::take();
11 let system = peripherals.SYSTEM.split();
12 let clocks = ClockControl::max(system.clock_control).freeze();
13
14 println!("Hello world!");
15
16 loop {}
10 esp_println::logger::init_logger_from_env();
11
12 let delay = Delay::new();
13 loop {
14 info!("Hello world!");
15 delay.delay(500.millis());
16 }
17 }
```

Inside the `main` function we can find:
- `let peripherals = Peripherals::take()`
- HAL drivers usually take ownership of peripherals accessed via the PAC
- Here we take all the peripherals from the PAC to pass them to the HAL drivers later
- `let mut system = peripherals.SYSTEM.split();`
- Sometimes a peripheral (here the System peripheral) is coarse-grained and doesn't exactly fit the HAL drivers - so here we split the System peripheral into smaller pieces which get passed to the drivers
- `let clocks = ClockControl::max(system.clock_control).freeze();`
- Here we configure the system clocks - in this case, boost to the maxiumum for the chip
- We freeze the clocks, which means we can't change them later
- Some drivers need a reference to the clocks to know how to calculate rates and durations
- `println!("Hello world!");`
- Prints "Hello world!"
- `esp_println::logger::init_logger_from_env();`
- Initializes the logger, if `ESP_LOG` environment variable is defined, it will use that log level.
- `let delay = Delay::new();`
- Creates a delay instance.
- `loop {}`
- Since our function is supposed to never return, we just "do nothing" in a loop
- Since our function is supposed to never return, we use a loop
- `info!("Hello world!");`
- Creates a log message with `info` level that prints "Hello world!".
- `delay.delay(500.millis());`
- Waits for 500 milliseconds.

[diverging-function]: https://doc.rust-lang.org/beta/rust-by-example/fn/diverging.html

Expand All @@ -114,7 +117,7 @@ Inside the `main` function we can find:
Building and running the code is as easy as

```shell
cargo run
cargo run --release
```

This builds the code according to the configuration and executes [`espflash`][espflash] to flash the code to the board.
Expand All @@ -127,26 +130,26 @@ Make sure that you have [`espflash`][espflash] installed, otherwise this step wi
You should see something similar to this:

```text
[2023-04-17T14:17:08Z INFO ] Serial port: '/dev/ttyACM0'
[2023-04-17T14:17:08Z INFO ] Connecting...
[2023-04-17T14:17:09Z INFO ] Using flash stub
[2023-04-17T14:17:09Z WARN ] Setting baud rate higher than 115,200 can cause issues
...
[2024-11-14T09:29:32Z INFO ] Serial port: '/dev/ttyUSB0'
[2024-11-14T09:29:32Z INFO ] Connecting...
[2024-11-14T09:29:32Z INFO ] Using flash stub
[2024-11-14T09:29:33Z WARN ] Setting baud rate higher than 115,200 can cause issues
Chip type: esp32c3 (revision v0.3)
Crystal frequency: 40MHz
Crystal frequency: 40 MHz
Flash size: 4MB
Features: WiFi, BLE
MAC address: 60:55:f9:c0:39:7c
App/part. size: 203,920/4,128,768 bytes, 4.94%
MAC address: a0:76:4e:5a:d2:c8
App/part. size: 76,064/4,128,768 bytes, 1.84%
[00:00:00] [========================================] 13/13 0x0
[00:00:00] [========================================] 1/1 0x8000
[00:00:01] [========================================] 64/64 0x10000
[2023-04-17T14:17:11Z INFO ] Flashing has completed!
[00:00:00] [========================================] 11/11 0x10000
[2024-11-14T09:29:35Z INFO ] Flashing has completed!
Commands:
CTRL+R Reset chip
CTRL+C Exit

...
Hello world!
INFO - Hello world!
```

What you see here are messages from the first and second stage bootloader, and then, our "Hello world" message!
Expand All @@ -157,6 +160,8 @@ You can reboot with `CTRL+R` or exit with `CTRL+C`.

If you encounter any issues while building the project, please, see the [Troubleshooting][troubleshooting] chapter.


[prelude]: https://doc.rust-lang.org/reference/names/preludes.html
[espflash]: https://github.com/esp-rs/espflash/tree/main/espflash
[runner-config]: https://doc.rust-lang.org/cargo/reference/config.html#targettriplerunner
[troubleshooting]: ../../troubleshooting/index.md
51 changes: 34 additions & 17 deletions src/writing-your-own-application/generate-project/index.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,46 @@
# Generating Projects from Templates

We currently maintain two template repositories:
- [`esp-template`][esp-template] - `no_std` template.
- [`esp-generate`][esp-generate] - `no_std` template.
- [`esp-idf-template`][esp-idf-template] - `std` template.

Both templates are based on [`cargo-generate`][cargo-generate], a tool that allows you to create a new project based on some existing template. In our case, [`esp-idf-template`][esp-idf-template] or [`esp-template`][esp-template] can be used to generate an application with all the required configurations and dependencies.

## `esp-generate`

`esp-generate` is project generation tool that can be used to generate an application with all the required configurations and dependencies

1. Install `esp-generate`:
```shell
cargo install esp-generate
```
2. Generate a project based on the template, selecting the chip and the name of the project:
```shell
esp-generate --chip=esp32c6 your-project
```
See [Understanding `esp-generate`][understanding-esp-generate] for more details on the template project.

When the `esp-generate` subcommand is invoked, you will be prompted with a TUI where you can select the configuration of your application. Upon completion of this process, you will have a buildable project with all the correct configurations.

3. Build/Run the generated project:
- Use `cargo build` to compile the project using the appropriate toolchain and target.
- Use `cargo run` to compile the project, flash it, and open a serial monitor with our target device.

[esp-generate]: https://github.com/esp-rs/esp-generate
[understanding-esp-generate]: ./esp-generate.md

## `esp-idf-template`

`esp-idf-tempalte` is based on [`cargo-generate`][cargo-generate], a tool that allows you to create a new project based on some existing template. In our case, [`esp-idf-template`][esp-idf-template] can be used to generate an application with all the required configurations and dependencies.

1. Install `cargo generate`:
```shell
cargo install cargo-generate
```
2. Generate a project based on one of the templates:
- `esp-template`:
```shell
cargo generate esp-rs/esp-template
```
See [Understanding `esp-template`][understanding-esp-template] for more details on the template project.
- `esp-idf-template`:
```shell
cargo generate esp-rs/esp-idf-template cargo
```
See [Understanding `esp-idf-template`][understanding-esp-idf-template] for more details on the template project.
2. Generate a project based on the template:
```shell
cargo generate esp-rs/esp-idf-template cargo
```
See [Understanding `esp-idf-template`][understanding-esp-idf-template] for more details on the template project.

When the `cargo generate` subcommand is invoked, you will be prompted to answer several questions regarding the target of your application. Upon completion of this process, you will have a buildable project with all the correct configurations.

Expand All @@ -30,17 +50,14 @@ Both templates are based on [`cargo-generate`][cargo-generate], a tool that allo

[cargo-generate]: https://github.com/cargo-generate/cargo-generate
[esp-idf-template]: https://github.com/esp-rs/esp-idf-template
[esp-template]: https://github.com/esp-rs/esp-template
[understanding-esp-template]: ./esp-template.md
[understanding-esp-idf-template]: ./esp-idf-template.md

## Using Dev Containers in the Templates

Both template repositories have a prompt for Dev Containers support, see details in [Dev Containers][dev-container] section of the template README.
Both template repositories have a prompt for Dev Containers support.

Dev Containers use the [`idf-rust`][idf-rust] container image, which was explained in the [Using Container][using-container] section of the [Setting up a Development Environment][setting-env] chapter. This image provides an environment ready to develop Rust applications for Espressif chips with no installation required. Dev Containers also have integration with [Wokwi simulator][wokwi], to simulate the project, and allow flashing from the container using [`web-flash`][web-flash].

[dev-container]: https://github.com/esp-rs/esp-template/tree/main/docs#dev-containers
[idf-rust]: https://hub.docker.com/r/espressif/idf-rust/tags
[using-container]: ../../installation/using-containers.md
[wokwi]: https://wokwi.com/
Expand Down
Loading