Skip to content

Commit

Permalink
Add documentation for the new builtin 'avr-unknown-gnu-atmega328' target
Browse files Browse the repository at this point in the history
This was added to Rust in rust-lang/rust#74941
  • Loading branch information
dylanmckay committed Sep 3, 2020
1 parent 33bd7bc commit 9fa5566
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 9 deletions.
40 changes: 31 additions & 9 deletions src/003-building-a-crate-for-avr.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@

After setting up the compiler, you may use it to generate assembly or machine code targeting a specific AVR microcontroller model.

## Choosing a `--target`

The Rust nightly compiler includes a built-in target for ATmega328 named `avr-unknown-gnu-atmega328`

If you wish to target a microcontroller other than ATmega328, or you want to change any of the
default builtin options like the linking parameters, then you will need to export the builtin
`avr-unknown-gnu-atmega328` target to a custom target specification JSON file and modify
it to suit your needs.

This target can be adapted to other microcontrollers as per the instructions in [3.1. The built-in `avr-unknown-gnu-atmega328` target](./003.1-the-avr-unknown-gnu-atmega328-target.md).

In summary, there are two options:

* Use `rustc --target=avr-unknown-gnu-atmega328` to use the default, builtin GCC based target for ATmega328
* Or use `rustc --target=my-custom-avr-target.json` with either a JSON file adapted from the builtin
`avr-unknown-gnu-atmega328` target above, or otherwise build the file manually you wish to avoiding the
default path entirely.

## Make sure you use the nightly version of Rust, not the default stable channel

The best way to ensure a crate is using the Nightly compiler is to run `rustup override set nightly` inside a terminal
Expand All @@ -12,25 +30,29 @@ any time `cargo` is used within the directory tree of the crate.

To compile and link an executable crate for AVR, run the following:

Using the builtin `avr-unknown-gnu-atmega328` target:

```rust
cargo build -Z build-std=core --target avr-unknown-gnu-atmega328 --release
```

Using a custom target specification JSON:


```rust
$ cargo build -Z build-std=core --target avr-atmega328p.json --release
cargo build -Z build-std=core --target /path/to/my-custom-avr-target.json --release
```

This will generate an AVR ELF file that can be subsequently flashed to a real device or ran inside a simulator.
The ELF file will be available at `target/<TARGET JSON NAME>/release/<CRATE NAME>.elf`.
Either or these generate an AVR ELF file that can be subsequently flashed to a real device or ran inside a simulator.
The ELF file will be available at `target/<TARGET NAME>/release/<CRATE NAME>.elf`.

Notes:

* **`-Z build-std=core` is required whenever AVR is being targeted**. See [3.1. A note about the required Rust `-Z build-std=<CRATE,>` flag](./003.1-note-about-rust-build-std-flag.md) for more details.
* **A target specification JSON file should almost always be specified**. There is a default target of `avr-unknown-unknown`, but this
target should be avoided in virtually all real-life usecases[CITATION NEEDED]. The `avr-unknown-unknown` target is equivalent to the AVR-GCC default, partially-microcontroller-independent mode where the lowest common denominator - the `avr2` family - is targeted.
* `--release` is not strictly required - debug mode should be as correct as release mode - however, **debug mode generates SLOW CODE, especially on AVR**. Release mode is much better.

**Example**: An in-context example of compiling a crate is given for the LED blinking example in [3.2. Example - Building the `blink` program for AVR](./003.2-example-building-blink.md).

### Targeting a different microcontroller model

Other models of AVR can be targeted by simply modifying the `cpu` field inside the target specification JSON. Each desired target microcontroller
variant requires its own target specification JSON file differing only by the `cpu` field. You will find many of the existing AVR projects
provide an-tree target specification JSON file only for the popular `atmega328p`, so you will in general need to duplicate the file and edit the `cpu`
to get a crate compiling on a non-atmega328p microcontroler.
The recommended way to do this is with a custom target specification JSON file per the instructions in [3.1. The built-in `avr-unknown-gnu-atmega328` target](./003.1-the-avr-unknown-gnu-atmega328-target.md).
74 changes: 74 additions & 0 deletions src/003.1-the-avr-unknown-gnu-atmega328-target.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# 3.1. The built-in `avr-unknown-gnu-atmega328` target

The Rust nightly compiler contains a built-in target, `avr-unknown-gnu-atmega328`, that
generates code for the AVR [ATmega328](https://en.wikipedia.org/wiki/ATmega328) using the
GNU AVR-GCC toolchain for linking support.

## Targeting custom microcontrollers by adapting 'avr-unkonwn-gnu-atmega328'

See the section [./005.1-the-target-specification-json-file.md](5.1. The Target Specification JSON File) for
more information about how Rust target specification JSON files work.

To generate a Rust target specification JSON file from the builtin:


```bash
rustc --print target-spec-json -Z unstable-options --target avr-unknown-gnu-atmega328 > my-custom-avr-unknown-gnu-atmega328.json
```

This prints the target specification JSON file `my-custom-avr-unknown-gnu-atmega328.json`:

```json
{
"arch": "avr",
"cpu": "atmega328",
"data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8",
"eh-frame-header": false,
"env": "",
"exe-suffix": ".elf",
"executables": true,
"is-builtin": true,
"late-link-args": {
"gcc": [
"-lgcc"
]
},
"linker": "avr-gcc",
"linker-flavor": "gcc",
"linker-is-gnu": true,
"llvm-target": "avr-unknown-unknown",
"os": "unknown",
"pre-link-args": {
"gcc": [
"-mmcu=atmega328",
"-Wl,--as-needed"
]
},
"target-c-int-width": "16",
"target-endian": "little",
"target-pointer-width": "16",
"vendor": "unknown"
}
```

To adapt this file to target a different microcontroller:

* Replace the top-level `"cpu": "atmega328"` with `"cpu": "YOUR-AVR-VARIANT-NAME"`
* Replace `"-mmcu=atmega328"` with `"-mmcu=YOUR-AVR-VARIANT-NAME"`

The file can then be passed to Rust via the `rustc --target <JSON FILE PATH>` instead of
`rustc --target avr-unknown-gnu-atmega328`, which will tailor the generated code to your
desired microcontroller.

It is also possible to customize link parameters if desired by modifying the JSON file.

## Compiling for AVR without the GNU toolchain

At the moment, the only builtin AVR target `avr-unknown-gnu-atmega328` always requires
AVR-GCC, AVR-libc and AVR-binutils from the GNU project.

The LLVM LLD linker has some limited support for AVR which in the future could be leveraged
to allow compiling AVR Rust binaries without the dependency on the GNU toolchain. Some work
on `compiler-builtins` and others would also be required. At the moment, the GNU toolchain
is a hard dependency.
no t
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- [2. Installing the compiler](./002-installing-the-compiler.md)
- [Installing required third party tools](./002.1-installing-required-third-party-tools.md)
- [3. Building a crate for AVR](./003-building-a-crate-for-avr.md)
- [The built-in `avr-unknown-gnu-atmega328` target](./003.1-the-avr-unknown-gnu-atmega328-target.md)
- [A note about the required Rust `-Z build-std=<CRATE,>` flag](./003.2-note-about-rust-build-std-flag.md)
- [Example - Building the `blink` program for AVR](./003.3-example-building-blink.md)
- [4. Flashing a crate to a real AVR chip](./004-flashing-a-crate-to-chip.md)
Expand Down

0 comments on commit 9fa5566

Please sign in to comment.