From 37d05b9ae6fbe2aad46678563653be4350283815 Mon Sep 17 00:00:00 2001 From: Johann Hemmann Date: Wed, 7 Jul 2021 17:10:23 +0200 Subject: [PATCH 1/5] `book` First refactor-through * `setup`: Deduplicate setup * `setup-app`: name `cargo.toml`; add `defmt-itm` * `macros`: Language * `primitives`: Table-ize and drop `u24` (got dropped in (#521)) * `str`: Add links to doc-rs * ... --- book/src/SUMMARY.md | 1 - book/src/bitfields.md | 32 ++++++++-------- book/src/filtering.md | 22 +++++------ book/src/format-slices.md | 31 +++++++++------ book/src/format.md | 18 +++++---- book/src/global-logger.md | 23 +++++++++++- book/src/hints.md | 79 ++++++++++++++++++++++----------------- book/src/istr.md | 28 ++++++++------ book/src/macros.md | 46 ++++++++++++++++------- book/src/panic.md | 25 ++++++------- book/src/primitives.md | 35 +++++++++++------ book/src/printers.md | 6 ++- book/src/setup-app.md | 41 +++++++------------- book/src/setup-library.md | 18 --------- book/src/setup.md | 34 ++++++++++++++++- book/src/timestamps.md | 13 ++++--- 16 files changed, 267 insertions(+), 185 deletions(-) delete mode 100644 book/src/setup-library.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index b25b8079..1d3917e9 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -3,7 +3,6 @@ [Introduction](./introduction.md) - [User guide](./user-guide.md) - [Setup](./setup.md) - - [Libraries](./setup-library.md) - [Applications](./setup-app.md) - [Logging macros](./macros.md) - [Primitives](./primitives.md) diff --git a/book/src/bitfields.md b/book/src/bitfields.md index 6bafe7b8..22d03f28 100644 --- a/book/src/bitfields.md +++ b/book/src/bitfields.md @@ -1,8 +1,13 @@ # Bitfields -`:m..n` is the bitfield formatting parameter. -When paired with a positional parameter it can be used to display the bitfields of a register. +> `:M..N` is the bitfield formatting parameter. + +The bitfield argument is expected to be a *unsigned* integer that's large enough to contain the bitfields. +For example, if bitfield ranges only cover up to bit `11` (e.g. `=8..12`) then the argument must be at least `u16`. +Bit indices are little-endian: the 0th bit is the rightmost bit. + +When paired with a positional parameter it can be used to display the bitfields of a register. ``` rust # extern crate defmt; # let pcnf1 = 0u32; @@ -14,20 +19,17 @@ defmt::trace!( ); ``` -The bitfield argument is expected to be a *fully typed, unsigned* integer that's large enough to contain the bitfields. -For example, if bitfield ranges only cover up to bit `11` (e.g. `=8..12`) then the argument must be `u16`. - -Bit indices are little-endian: the 0th bit is the rightmost bit. - -Bitfields are not range inclusive, e.g. +Bitfields are not range inclusive, e.g. following statement will evaluate to `5` (`0b110`): ``` rust # extern crate defmt; -defmt::trace!("first two bits: {0=0..3}", 254u32); +// -> TRACE: first three bits: 110 +defmt::trace!("first three bits: {0=0..3}", 254u32); ``` -will evaluate to `2` (`0b10`). -⚠️ You can not reuse the same argument in a bitfield- and a non bitfield parameter. This will not compile: -``` rust,compile_fail -# extern crate defmt; -defmt::trace!("{0=5..13} {0=u16}", 256u16); -``` +> ⚠️ You can not reuse the same argument in a bitfield- and a non bitfield parameter. +> +> This will not compile: +> ``` rust,compile_fail +> # extern crate defmt; +> defmt::trace!("{0=5..13} {0=u16}", 256u16); +> ``` diff --git a/book/src/filtering.md b/book/src/filtering.md index cd202b33..e91fe3a2 100644 --- a/book/src/filtering.md +++ b/book/src/filtering.md @@ -2,21 +2,21 @@ `defmt` supports 5 different logging levels listed below from lowest severity to highest severity: -- TRACE -- DEBUG -- INFO -- WARN -- ERROR +- `TRACE` +- `DEBUG` +- `INFO` +- `WARN` +- `ERROR` By default all logging is *disabled*. The amount of logging to perform can be controlled at the *crate* level using the following Cargo features: -- `defmt-default`, log at INFO, or TRACE, level and up -- `defmt-trace`, log at TRACE level and up -- `defmt-debug`, log at DEBUG level and up -- `defmt-info`, log at INFO level and up -- `defmt-warn`, log at WARN level and up -- `defmt-error`, log at ERROR level +- `defmt-trace`, log at `TRACE` level and up +- `defmt-debug`, log at `DEBUG` level and up +- `defmt-info`, log at `INFO` level and up +- `defmt-warn`, log at `WARN` level and up +- `defmt-error`, log at `ERROR` level +- `defmt-default`, log at `INFO`, or `TRACE`, level and up These features must only be enabled by the top level *application* crate as shown below. diff --git a/book/src/format-slices.md b/book/src/format-slices.md index d7f80c52..f5238f2b 100644 --- a/book/src/format-slices.md +++ b/book/src/format-slices.md @@ -1,38 +1,47 @@ # Format slices / arrays -The `{=[?]}` parameter can be used to log a slices of values that implement the `Format` trait. -The expected argument is a slice. +> The `{=[?]}` parameter can be used to log a slice of values that implement the `Format` trait. ``` rust # extern crate defmt; -# use defmt::{Format, info}; +# use defmt::Format; +# #[derive(Format)] struct X { y: u16, z: u8, } -let xs: &[X] = &[/* .. */]; -info!("xs={=[?]}", xs); + +let xs: &[X] = &[ /* .. */ ]; +defmt::info!("xs={=[?]}", xs); ``` -Note that for slices of bytes `{=[u8]}` should be preferred as it's better compressed. -`[T] where T: Format` also implements the `Format` trait so it's possible to format `[T]` with `{=?}` but `{=[?]}` uses slightly less bandwidth. +* The expected argument is a slice. + +* Note that for slices of bytes, `{=[u8]}` should be preferred as it's better compressed. + +* `[T] where T: Format` also implements the `Format` trait so it's possible to format `[T]` with `{=?}` but `{=[?]}` uses slightly less bandwidth. -If you have an array of types that implement the `Format` trait, instead of a slice. You should use -the `{=[?; N]}` parameter (where `N` is a number); this saves bandwidth compared to `{=[?]}`. + +## Arrays + +If you have an array of types that implement the `Format` trait, you should use +the `{=[?; N]}` parameter (where `N` is the number of elements); this saves bandwidth compared to `{=[?]}`. ``` rust # extern crate defmt; -# use defmt::{Format, info}; +# use defmt::Format; +# #[derive(Format)] struct X { y: u16, z: u8, } + let xs: [X; 2] = [ # X { y: 1, z: 2 }, # X { y: 3, z: 4 }, // .. ]; -info!("xs={=[?; 2]}", xs); +defmt::info!("xs={=[?; 2]}", xs); ``` diff --git a/book/src/format.md b/book/src/format.md index c4f92fab..d6fc4407 100644 --- a/book/src/format.md +++ b/book/src/format.md @@ -1,8 +1,13 @@ # Implementing `Format` +- [`#[derive(Format)]`](#deriveformat) +- [Manual implementation with `write!`](#manual-implementation-with-write) +- [Newtypes](#newtypes) +- [Uncompressed adapters](#uncompressed-adapters) + ## `#[derive(Format)]` -The easiest way to implement the `Format` trait for a struct or enum is to use the `derive` attribute. +The easiest way to implement the `Format` trait for a `struct` or `enum` is to use the `derive` attribute. ``` rust # extern crate defmt; @@ -17,6 +22,7 @@ struct Header { # #[derive(Format)] # struct Descriptor; +# #[derive(Format)] enum Request { GetDescriptor { descriptor: Descriptor, length: u16 }, @@ -24,13 +30,11 @@ enum Request { } ``` -NOTE: Like built-in derives like `#[derive(Debug)]`, `#[derive(Format)]` will add `Format` bounds to the generic type parameters of the struct. - -NOTE: Do *not* use the API used by the expansion of the `derive(Format)` macro; it is *unstable*. +Like built-in derives (e.g. `#[derive(Debug)]`), `#[derive(Format)]` will add `Format` bounds to the generic type parameters of the struct. -## `write!` +> ⚠️ Do *not* use the API used by the expansion of the `derive(Format)` macro; it is *unstable*. -> NOTE `write!` is available in `defmt` v0.1.**2**+ +## Manual implementation with `write!` It is also possible to implement the `Format` trait manually. This trait has a single required method: `format`. @@ -76,7 +80,7 @@ impl defmt::Format for MyU8 { If you quickly want to get some code running and do not care about it being efficient you can use the two adapter types [`Display2Format`] and [`Debug2Format`]. -These adapters disable compression and use the `core::fmt` code on-device! You should always prefer `defmt::Format` over `Debug` whenever possible. +> ⚠️ These adapters disable compression and use the `core::fmt` code on-device! You should always prefer `defmt::Format` over `Debug` whenever possible! Note that this always uses `{:?}` to format the contained value, meaning that any provided defmt display hints will be ignored. diff --git a/book/src/global-logger.md b/book/src/global-logger.md index b8f96c4b..0a6e0851 100644 --- a/book/src/global-logger.md +++ b/book/src/global-logger.md @@ -1,6 +1,7 @@ # #[global_logger] -*Applications* that, directly or transitively, use any of `defmt` logging macros need to define a `#[global_logger]` or include one in their dependency graph. +> *Applications* that, directly or transitively, use any of `defmt` logging macros need to define a `#[global_logger]` or include one in their dependency graph. + This is similar to how the `alloc` crate depends on a `#[global_allocator]`. The `global_logger` defines how data is moved from the *device*, where the application runs, to the host, where logs will be formatted and displayed. @@ -20,6 +21,26 @@ Finally, `#[global_logger]` specifies which `Logger` implementation will be used `#[global_logger]` must be used on a *unit* struct, a struct with no fields. This struct must implement the `Logger` trait. It's recommended that this struct is kept private. + +```rust +# extern crate defmt; +# +#[defmt::global_logger] +struct Logger; + +unsafe impl defmt::Logger for Logger { + fn acquire() { + // ... + } + unsafe fn release() { + // ... + } + unsafe fn write(bytes: &[u8]) { + // ... + } +} +``` + Only a single `#[global_logger]` struct can appear in the dependency graph of an application. The `global_logger` should be selected *at the top* of the dependency graph, that is in the application crate. diff --git a/book/src/hints.md b/book/src/hints.md index 82fe78c3..b4bb8dc6 100644 --- a/book/src/hints.md +++ b/book/src/hints.md @@ -1,54 +1,71 @@ # Display hints -A hint can be applied to each formatting parameter to change how it's printed on the host side. -The hint follows the syntax `:x` and must come after the type within the braces. -Examples: typed `{=u8:x}`, untyped `{:b}` +> A hint can be applied to each formatting parameter to change how it's printed on the host side. + +The hint follows the syntax `:Display` and must come after the type within the braces, for example: +* typed `{=u8:x}` +* untyped `{:b}` The following display hints are currently supported: -- `x`, lowercase hexadecimal -- `X`, uppercase hexadecimal -- `?`, `core::fmt::Debug`-like -- `b`, binary -- `a`, ASCII -- `us`, microseconds (formats integers as time stamps) +| hint | name | +| :---- | :--------------------------------------------- | +| `:x` | lowercase hexadecimal | +| `:X` | uppercase hexadecimal | +| `:?` | `core::fmt::Debug`-like | +| `:b` | binary | +| `:a` | ASCII | +| `:us` | microseconds (formats integers as time stamps) | -The first 4 display hints resemble what's supported in `core::fmt`. Examples below: +The first 4 display hints resemble what's supported in `core::fmt`, for example: ``` rust # extern crate defmt; -defmt::info!("{=u8:x}", 42); // -> INFO 2a -defmt::info!("{=u8:X}", 42); // -> INFO 2A +defmt::info!("{=u8:x}", 42); // -> INFO 2a +defmt::info!("{=u8:X}", 42); // -> INFO 2A defmt::info!("{=u8:#x}", 42); // -> INFO 0x2a -defmt::info!("{=u8:b}", 42); // -> INFO 101010 +defmt::info!("{=u8:b}", 42); // -> INFO 101010 defmt::info!("{=str}", "hello\tworld"); // -> INFO hello world defmt::info!("{=str:?}", "hello\tworld"); // -> INFO "hello\tworld" ``` -Leading zeros are supported, for example +The ASCII display hint formats byte slices (and arrays) using Rust's byte string syntax. ``` rust # extern crate defmt; -defmt::info!("{=u8:03}", 42); // -> INFO 042 -defmt::info!("{=u8:08X}", 42); // -> INFO 0000002A -defmt::info!("{=u8:#010X}", 42); // -> INFO 0x0000002A +let bytes = [104, 101, 255, 108, 108, 111]; + +defmt::info!("{=[u8]:a}", bytes); // -> INFO b"he\xffllo" ``` -When the alternate form is used for hex and binary, the `0x`/`0b` length is subtracted from the -leading zeros. This matches [`core::fmt` behavior](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b11809759f975e266251f7968e542756). No further -customization is supported (at the moment). +## Alternate printing -The ASCII display hint formats byte slices (and arrays) using Rust's byte string syntax. +Adding `#` in front of a binary and hexadecimal display hints, precedes these numbers with a base indicator. ``` rust # extern crate defmt; -let bytes = [104, 101, 255, 108, 108, 111]; +defmt::info!("{=u8:b}", 42); // -> INFO 101010 +defmt::info!("{=u8:#b}", 42); // -> INFO 0b101010 +defmt::info!("{=u8:x}", 42); // -> INFO 2a +defmt::info!("{=u8:#x}", 42); // -> INFO 0x2a +defmt::info!("{=u8:X}", 42); // -> INFO 2A +defmt::info!("{=u8:#X}", 42); // -> INFO 0x2A +``` -defmt::info!("{=[u8]:a}", bytes); -// -> INFO b"he\xffllo" +## Zero padding + +Padding numbers with leading zeros is supported, for example: + +``` rust +# extern crate defmt; +defmt::info!("{=u8:03}", 42); // -> INFO 042 +defmt::info!("{=u8:08X}", 42); // -> INFO 0000002A +defmt::info!("{=u8:#010X}", 42); // -> INFO 0x0000002A ``` +When the alternate form is used for hex and binary, the `0x`/`0b` length is subtracted from the leading zeros. This matches [`core::fmt` behavior](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b11809759f975e266251f7968e542756). + ## Propagation Display hints "propagate downwards" and apply to formatting parameters that specify no display hint. @@ -59,11 +76,8 @@ Display hints "propagate downwards" and apply to formatting parameters that spec struct S { x: u8 } let x = S { x: 42 }; -defmt::info!("{}", x); -// -> INFO S { x: 42 } - -defmt::info!("{:#x}", x); -// -> INFO S { x: 0x2a } +defmt::info!("{}", x); // -> INFO S { x: 42 } +defmt::info!("{:#x}", x); // -> INFO S { x: 0x2a } ``` ``` rust @@ -78,9 +92,6 @@ impl defmt::Format for S { } let x = S { x: 42, y: 42 }; -defmt::info!("{}", x); -// -> INFO S { x: 42, y: 2a } - -defmt::info!("{:b}", x); -// -> INFO S { x: 101010, y: 2a } +defmt::info!("{}", x); // -> INFO S { x: 42, y: 2a } +defmt::info!("{:b}", x); // -> INFO S { x: 101010, y: 2a } ``` diff --git a/book/src/istr.md b/book/src/istr.md index f885634c..ce8215a1 100644 --- a/book/src/istr.md +++ b/book/src/istr.md @@ -1,9 +1,11 @@ # Interned strings -The `{=istr}` formatting parameter is used for *interned* strings. +> The `{=istr}` formatting parameter is used for *interned* strings. + Compared to the `{=str}` parameter, which transmits a complete string, `{=istr}` saves bandwidth by sending only a string index. -The `{=istr}` parameter expects an argument with type `defmt::Str`. -A `Str` value is created using the `intern!` macro; the argument to this macro must be a string literal. + +The `{=istr}` parameter expects an argument with type [`defmt::Str`]. +A `Str` value is created using the [`intern!`] macro; the argument to this macro must be a string literal. ``` rust # extern crate defmt; @@ -14,15 +16,17 @@ defmt::info!("{=str}", s); # use defmt::Str; let interned: Str = defmt::intern!("The quick brown fox jumps over the lazy dog"); defmt::info!("{=istr}", interned); -// ^^^^^^^^ bandwidth-use <= 2 bytes +// ^^^^^^^^^ bandwidth-use <= 2 bytes ``` -This was a contrived example to show the difference in bandwidth use. -In practice you should use: - -``` rust -# extern crate defmt; -defmt::info!("The quick brown fox jumps over the lazy dog"); -``` +> ⚠️ This was a contrived example to show the difference in bandwidth use. +> +> In practice you should following, which also interns the log string and uses as little bandwidth as the `{=istr}` version: +> +> ``` rust +> # extern crate defmt; +> defmt::info!("The quick brown fox jumps over the lazy dog"); +> ``` -which also interns the log string and uses as little bandwidth as the `{=istr}` version. +[`defmt::Str`]: https://docs.rs/defmt/*/defmt/struct.Str.html +[`intern!`]: https://docs.rs/defmt/*/defmt/macro.intern.html \ No newline at end of file diff --git a/book/src/macros.md b/book/src/macros.md index fbddaaae..57027526 100644 --- a/book/src/macros.md +++ b/book/src/macros.md @@ -1,31 +1,27 @@ # Logging macros -Logging is done using the `error`, `warn`, `info`, `debug` and `trace` macros. -Each macro logs at the logging level indicated in its name. -The syntax of these macros is roughly the same as the `println` macro. -Positional parameters are supported but named parameters are not. -Escaping rules are the same: the characters `{` and `}` are escaped as `{{` and `}}`. -The biggest difference is in the supported formatting parameters (`:?`, `:>4`, `:04`). +> Logging is done using the `error!`, `warn!`, `info!`, `debug!` and `trace!` macros. + +Each macro logs at the logging level indicated by its name. +The syntax of these macros is roughly the same as the `println`-macro. ``` rust # extern crate defmt; # let len = 80u8; // -> INFO: message arrived (length=80) -defmt::info!( - "message arrived (length={})", - len /*: usize */, -); +defmt::info!("message arrived (length={})", len); # struct Message; # impl Message { fn header(&self) -> u8 { 0 } } # let message = Message; // -> DEBUG: Header { source: 2, destination: 3, sequence: 16 } -defmt::debug!("{:?}", message.header() /*: Header */); +defmt::debug!("{:?}", message.header()); ``` +## The `Format` trait + Unlike `core::fmt` which has several formatting traits (`Debug`, `Display`), `defmt` has a single formatting trait called `Format`. -The `{}` formatting parameter indicates that the `Format` trait will be used. -When `{}` is used the corresponding argument must implement the `Format` trait. +The `{}` formatting parameter indicates that the `Format` trait will be used, meaning the argument must implement the `Format` trait. ``` rust # extern crate defmt; @@ -33,3 +29,27 @@ When `{}` is used the corresponding argument must implement the `Format` trait. defmt::trace!("{}", x); // ^ must implement the `Format` trait ``` + +## Type and display hints + +The `defmt` grammer is similar to `core::fmt`, but not the same. It works like following: + +> `{[pos][=Type][:Display]}` + +### Type hint + +The `Type` hint always starts with a `=`. +For once it enables the framework to further compress the logs resulting in higher throughput. +Secondly it also typechecks the supplied value to fit the specified type. + +The type hint can be a [primitive](./primitives.md) or [one](./format-slices.md), [of](./istr.md), [the](./bitfields.md) special types. +Read on to learn more about the type hints. + +### Display hint + +The `Display` hint, always starts with a `:` and specifies the printing on the host side. +Read more about it [here](./hints.md). + +### Positional parameter + +The `pos` parameter lets you specify the position of the value to format (see ["Positional parameters"](https://doc.rust-lang.org/std/fmt/index.html#positional-parameters)). diff --git a/book/src/panic.md b/book/src/panic.md index a0463961..7fbf75b9 100644 --- a/book/src/panic.md +++ b/book/src/panic.md @@ -1,27 +1,25 @@ # `panic!` and `assert!` -> NOTE all these macros are available in `defmt` v0.1.**2**+ +> The `defmt` crate provides its own version of `panic!`-like and `assert!`-like macros. -The `defmt` crate provides its own version of `panic!`-like and `assert!`-like macros. The `defmt` version of these macros will log the panic message using `defmt` and then call `core::panic!` (by default). Because the panic message is formatted using `defmt!` the format string must use the same syntax as the logging macros (e.g. `info!`). ## `#[defmt::panic_handler]` -Because `defmt::panic!` invokes `core::panic!` this can result in the panic message being printed twice if your `#[core::panic_handler]` also prints the panic message. -This is the case if you use [`panic-probe`] with the `print-defmt` feature enabled but not an issue if you are using the [`panic-abort`] crate, for example. - -[`panic-probe`]: https://crates.io/crates/panic-probe -[`panic-abort`]: https://crates.io/crates/panic-abort +> You can use the `#[defmt::panic_handler]` to *override* the panicking behavior of the `defmt::panic!` and `defmt::assert!` macros. -To avoid this issue you can use the `#[defmt::panic_handler]` to *override* the panicking behavior of `defmt::panic`-like and `defmt::assert`-like macros. This attribute must be placed on a function with signature `fn() -> !`. -In this function you'll want to replicate the panicking behavior of the Rust `#[panic_handler]` but leave out the part that prints the panic message. + +This is for example useful, because `defmt::panic!` invokes `core::panic!` which can result in the panic message being printed twice if your `#[core::panic_handler]` also prints the panic message. +This is the case if you use [`panic-probe`] with the `print-defmt` feature enabled but not an issue if you are using the [`panic-abort`] crate, for example. + +To avoid this issue you can replicate the panicking behavior of the Rust `#[panic_handler]` but leave out the part that prints the panic message. For example: -``` rust, ignore +```rust, ignore #[panic_handler] // built-in ("core") attribute fn core_panic(info: &core::panic::PanicInfo) -> ! { print(info); // e.g. using RTT @@ -37,8 +35,9 @@ fn defmt_panic() -> ! { If you are using the `panic-probe` crate then you should "abort" (call `cortex_m::asm::udf`) from `#[defmt::panic_handler]` to match its behavior. -NOTE: even if you don't run into the "double panic message printed" issue you may still want to use `#[defmt::panic_handler]` because this way `defmt::panic` and `defmt::assert` will *not* go through the `core::panic` machinery and that *may* reduce code size (we recommend you measure the effect of the change). +Even if you don't run into the "double panic message printed" issue you may still want to use `#[defmt::panic_handler]` because this way `defmt::panic` and `defmt::assert` will *not* go through the `core::panic` machinery and that *may* reduce code size (we recommend you measure the effect of the change). -## Inter-operation with built-in attributes +> ⚠️ The `#[panic_handler]` attribute cannot be used together with the `export_name` or `no_mangle` attributes -The `#[panic_handler]` attribute cannot be used together with the `export_name` or `no_mangle` attributes +[`panic-probe`]: https://crates.io/crates/panic-probe +[`panic-abort`]: https://crates.io/crates/panic-abort \ No newline at end of file diff --git a/book/src/primitives.md b/book/src/primitives.md index 14b6225c..fe22147d 100644 --- a/book/src/primitives.md +++ b/book/src/primitives.md @@ -1,8 +1,17 @@ # Primitives -In addition to `{}` there are formatting parameters for several primitive types. -These parameters follow the syntax `{=Type}`, for example: `{=u8}`, `{=bool}`. -This type information lets the framework further compress the logs resulting in higher throughput. +Following **primitive types** are available: + +| type hint | name | +| :------------------- | :---------------------------------- | +| `=bool` | boolean | +| `={i,u}{8,16,32,64}` | standard integer types | +| `=f{32, 64}` | 32-bit / 64-bit floating point type | +| `=[u8; N]` | byte array | +| `=[u8]` | byte slice | +| `=str` | string slice | + +They can be used like this: ``` rust # extern crate defmt; @@ -21,13 +30,15 @@ defmt::trace!("{=u16}", x); // ^ must have type `u16` ``` -The available types are: +--- + +Additionally there are some **special types**: + +| type hint | name | +| :-------- | :--------------- | +| `=M..N` | Bitfields | +| `=istr` | Interned Strings | +| `=[?]` | Format slices | +| `=[?; N]` | Format arrays | -- `=bool`, boolean -- `={i,u}{8,16,32,64}`, standard integer types -- `={i,u}24`, 32-bit integer truncated to 24 bits -- `=f32`, 32-bit floating point type -- `=f64`, 64-bit floating point type -- `=[u8; N]`, byte array -- `=[u8]`, byte slice -- `=str`, string slice +Read more about them in the following chapters. diff --git a/book/src/printers.md b/book/src/printers.md index e99e2d79..a891f4c9 100644 --- a/book/src/printers.md +++ b/book/src/printers.md @@ -3,9 +3,11 @@ *Printers* are *host* programs that receive log data, format it and display it. The following printers are currently available: -- [`probe-run`], parses data sent over RTT (ARM Cortex-M only). NOTE: if you are using the git version of defmt, make sure you also install the tool from git (not crates.io). +- [`probe-run`], parses data sent over RTT (ARM Cortex-M only). + - ℹ️ If you are using the git version of defmt, make sure you also install the tool from git and not crates.io. - [`defmt-print`], a generic command-line tool that decodes defmt data passed into its standard input. -- [`qemu-run`], parses data sent by QEMU over semihosting (ARM Cortex-M only). NOTE: used for internal testing; won't be published to crates.io +- [`qemu-run`], parses data sent by QEMU over semihosting (ARM Cortex-M only). + - ℹ️ Used for internal testing and won't be published to crates.io [`probe-run`]: https://github.com/knurling-rs/probe-run [`defmt-print`]: https://github.com/knurling-rs/defmt/tree/main/print diff --git a/book/src/setup-app.md b/book/src/setup-app.md index 50214d71..13930caf 100644 --- a/book/src/setup-app.md +++ b/book/src/setup-app.md @@ -1,41 +1,24 @@ # Application setup -**NOTE** the preferred way to create a *new* `defmt` application is to use our [`app-template`]. -These steps are for using `defmt` on an *existing* application. - -[`app-template`]: https://github.com/knurling-rs/app-template - -## Cargo features - -Add these Cargo features to your app's `Cargo.toml`: - -``` toml -# Cargo.toml -# under the features section, copy these -[features] -# ↓↓↓↓↓ -defmt-default = [] -defmt-trace = [] -defmt-debug = [] -defmt-info = [] -defmt-warn = [] -defmt-error = [] -# ↑↑↑↑↑ -``` - ## Linker script The application must be linked using a custom linking process that includes the `defmt.x` linker script. Custom linking is usual for embedded applications and configured in the `.cargo/config` file. -To pass `defmt.x` to the linker add the `-C link-arg=-Tdefmt.x` flag to the rustflags section of `.cargo/config`. + +To pass `defmt.x` to the linker add the `-C link-arg=-Tdefmt.x` flag to the rustflags section of `.cargo/config.toml`. ``` toml -# .cargo/config +# .cargo/config.toml [target.thumbv7m-none-eabi] rustflags = [ - # likely, there's another `link-arg` flag already there; KEEP it + # --- KEEP existing `link-arg` flags --- "-C", "link-arg=-Tlink.x", - "-C", "link-arg=-Tdefmt.x", # <- ADD this one + + # --- ADD following new flags --- + "-C", "link-arg=-Tdefmt.x", + # This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x + # See https://github.com/rust-embedded/cortex-m-quickstart/pull/95 + "-C", "link-arg=--nmagic", ] ``` @@ -48,10 +31,12 @@ The `global_logger` can appear anywhere in the dependency graph and usually it w The following `global_logger`s are provided as part of the project: - [`defmt-rtt`], logs over RTT. Note that this crate can *not* be used together with `rtt-target`. +- [`defmt-itm`], logs over ITM (Instrumentation Trace Macrocell) stimulus port 0. - [`defmt-semihosting`], logs over semihosting. Meant only for testing `defmt` on a virtual Cortex-M device (QEMU). -[`defmt-semihosting`]: https://github.com/knurling-rs/defmt/tree/9f97c1fd562738159a142bd67c410c48ef8d4110/firmware/defmt-semihosting [`defmt-rtt`]: https://docs.rs/defmt-rtt/ +[`defmt-itm`]: https://docs.rs/defmt-rtt/ +[`defmt-semihosting`]: https://github.com/knurling-rs/defmt/tree/6cfd947384debb18a4df761cbe454f8d86cf3441/firmware/defmt-semihosting Information about how to write a `global_logger` can be found in the [`#[global_logger]` section](./global-logger.md). diff --git a/book/src/setup-library.md b/book/src/setup-library.md deleted file mode 100644 index c13fde55..00000000 --- a/book/src/setup-library.md +++ /dev/null @@ -1,18 +0,0 @@ -# Library setup - -If your library will use any of the logging macros (`trace!`, `debug!`, `info!`, `warn!`, `error!`) then you'll need to add these Cargo features to your library's `Cargo.toml`: - -``` toml -# under the features section, copy these -[features] -# ↓↓↓↓↓ -defmt-default = [] -defmt-trace = [] -defmt-debug = [] -defmt-info = [] -defmt-warn = [] -defmt-error = [] -# ↑↑↑↑↑ -``` - -You do not need to add these features if you are only going to use the `#[derive(Format)]` attribute. diff --git a/book/src/setup.md b/book/src/setup.md index d2f63890..1d6bbc69 100644 --- a/book/src/setup.md +++ b/book/src/setup.md @@ -1,4 +1,36 @@ # Setup Before you use the `defmt` crate some setup may be necessary. -The setup steps depends on whether you are using `defmt` from a library or an application. +There is some base setup needed for both libraries and applications and some additional steps only for applications. + +> 💡 The prefferred way to create a *new* `defmt` application is to use our [app-template]. Tag along if you want to add `defmt` to an *existing* appliaction. + +[app-template]: https://github.com/knurling-rs/app-template + +## Base setup + +If you only use the `#[derive(Format)]` attribute and no logging macros then you do not need do anything except adding `defmt` to your dependencies. + +```console +$ cargo add defmt +``` + +If your library/application will use any of the logging macros (`trace!`, `debug!`, `info!`, `warn!`, `error!`), which it will likely do, then you will need to add following Cargo features to your `Cargo.toml`: + +``` toml +[features] +existing-feature = [] + +# --- ADD THOSE --- +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] +``` + +--- + +That is already it for setting up `defmt` for your library! +See the next chapter for additional steps for applications. diff --git a/book/src/timestamps.md b/book/src/timestamps.md index cd5d2208..b4eca382 100644 --- a/book/src/timestamps.md +++ b/book/src/timestamps.md @@ -1,8 +1,8 @@ # Timestamps -*Applications* that, directly or transitively, use any of `defmt` logging macros may use the `timestamp!` macro to define additional data to be included in every log frame. +> *Applications* that, directly or transitively, use any of `defmt` logging macros may use the `timestamp!` macro to define additional data to be included in every log frame. -The `timestamp!` macro may only be used once throughout the crate graph. Its syntax is the same as for the other logging macros (`info!`, etc.), except that `timestamp!` is global and so cannot access any local variables. +The `timestamp!` macro may only be used once throughout the crate graph. Its syntax is the same as for the other logging macros, except that `timestamp!` is global and so cannot access any local variables. By default, no timestamp is provided or transferred over the defmt sink. @@ -39,10 +39,11 @@ defmt::timestamp!("{=u32:us}", { # fn enable_monotonic_counter() {} fn main() { - defmt::info!(".."); // timestamp = 0 + defmt::info!(".."); // timestamp = 0 defmt::debug!(".."); // timestamp = 0 + enable_monotonic_counter(); - defmt::info!(".."); // timestamp >= 0 + defmt::info!(".."); // timestamp >= 0 // .. } ``` @@ -73,8 +74,8 @@ To read the 64-bit value in a lock-free manner the following algorithm can be us ``` text do { high1: u32 <- read_high_count() - low : u32<- read_low_count() - high2 : u32<- read_high_count() + low : u32 <- read_low_count() + high2 : u32 <- read_high_count() } while (high1 != high2) count: u64 <- (high1 << 32) | low ``` From cbc4c0154959fcb9069f78ae30cf472bffcc606d Mon Sep 17 00:00:00 2001 From: Johann Hemmann Date: Tue, 13 Jul 2021 15:38:53 +0200 Subject: [PATCH 2/5] `book` Drop `trait Write` --- book/src/global-logger.md | 52 ++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/book/src/global-logger.md b/book/src/global-logger.md index 0a6e0851..7949e228 100644 --- a/book/src/global-logger.md +++ b/book/src/global-logger.md @@ -7,27 +7,16 @@ This is similar to how the `alloc` crate depends on a `#[global_allocator]`. The `global_logger` defines how data is moved from the *device*, where the application runs, to the host, where logs will be formatted and displayed. `global_logger` is transport agnostic: you can use a serial interface, serial over USB, RTT, semihosting, Ethernet, 6LoWPAN, etc. to transfer the data. -The `global_logger` interface comprises two traits, `Write` and `Logger`, and one attribute, `#[global_logger]`. +The `global_logger` interface comprises the trait `Logger` and the attribute, `#[global_logger]`. -The `Write` trait specifies how the data is put on the wire. -The `write` method is not allowed to fail. -Buffering, rather than waiting on I/O, is recommended. -If using buffering `write` should not overwrite old data as this can corrupt log frames and most printers cannot deal with incomplete log frames. - -The `Logger` specifies how to acquire and release a handle to a global logger. -See the API documentation for more details about the safety requirements of the acquire-release mechanism. +## The `Logger` trait -Finally, `#[global_logger]` specifies which `Logger` implementation will be used by the application. -`#[global_logger]` must be used on a *unit* struct, a struct with no fields. -This struct must implement the `Logger` trait. -It's recommended that this struct is kept private. +Firstly `Logger` specifies how to acquire and release a handle to a global logger, as well as how the data is put on the wire. ```rust # extern crate defmt; +# struct Logger; # -#[defmt::global_logger] -struct Logger; - unsafe impl defmt::Logger for Logger { fn acquire() { // ... @@ -41,8 +30,37 @@ unsafe impl defmt::Logger for Logger { } ``` -Only a single `#[global_logger]` struct can appear in the dependency graph of an application. -The `global_logger` should be selected *at the top* of the dependency graph, that is in the application crate. +The `write` method is not allowed to fail. +Buffering, rather than waiting on I/O, is recommended. +If using buffering `write` should not overwrite old data as this can corrupt log frames and most printers cannot deal with incomplete log frames. + +See the API documentation for more details about the safety requirements of the acquire-release mechanism. + + +## The `#[global_logger]` attribute + +Secondly, `#[global_logger]` specifies which `Logger` implementation will be used by the application. + +`#[global_logger]` must be used on a *unit* struct, a struct with no fields, which must implement the `Logger` trait. +It's recommended that this struct is kept private. + +```rust +# extern crate defmt; +# +#[defmt::global_logger] +struct Logger; + +unsafe impl defmt::Logger for Logger { + // ... + # fn acquire() {} + # unsafe fn release() {} + # unsafe fn write(bytes: &[u8]) {} +} +``` + +> ⚠️ Only a single `#[global_logger]` struct can appear in the dependency graph of an application. +> +> Therefore the `global_logger` should be selected *at the top* of the dependency graph, that is in the application crate. There are two general ways to implement a `global_logger`. From 1b9d1fb73a48095d437f3013d507c41528898f42 Mon Sep 17 00:00:00 2001 From: Johann Hemmann Date: Tue, 13 Jul 2021 21:55:53 +0200 Subject: [PATCH 3/5] Update during 2nd read-through --- book/src/filtering.md | 14 ++++++++------ book/src/format-slices.md | 12 ++++++------ book/src/format.md | 5 ----- book/src/global-logger.md | 3 ++- book/src/hints.md | 10 +++++++--- book/src/introduction.md | 4 ++-- book/src/macros.md | 2 +- book/src/panic.md | 2 +- book/src/printers.md | 4 ++-- 9 files changed, 29 insertions(+), 27 deletions(-) diff --git a/book/src/filtering.md b/book/src/filtering.md index e91fe3a2..a0d95cf0 100644 --- a/book/src/filtering.md +++ b/book/src/filtering.md @@ -11,12 +11,14 @@ By default all logging is *disabled*. The amount of logging to perform can be controlled at the *crate* level using the following Cargo features: -- `defmt-trace`, log at `TRACE` level and up -- `defmt-debug`, log at `DEBUG` level and up -- `defmt-info`, log at `INFO` level and up -- `defmt-warn`, log at `WARN` level and up -- `defmt-error`, log at `ERROR` level -- `defmt-default`, log at `INFO`, or `TRACE`, level and up +| Feature | Log at ... | +| :-------------- | :----------------------------------- | +| `defmt-trace` | ... `TRACE` level and up | +| `defmt-debug` | ... `DEBUG` level and up | +| `defmt-info` | ... `INFO` level and up | +| `defmt-warn` | ... `WARN` level and up | +| `defmt-error` | ... `ERROR` level | +| `defmt-default` | ... `INFO`, or `TRACE`, level and up | These features must only be enabled by the top level *application* crate as shown below. diff --git a/book/src/format-slices.md b/book/src/format-slices.md index f5238f2b..1df0916a 100644 --- a/book/src/format-slices.md +++ b/book/src/format-slices.md @@ -2,6 +2,8 @@ > The `{=[?]}` parameter can be used to log a slice of values that implement the `Format` trait. +The expected argument is a slice. + ``` rust # extern crate defmt; # use defmt::Format; @@ -16,11 +18,9 @@ let xs: &[X] = &[ /* .. */ ]; defmt::info!("xs={=[?]}", xs); ``` -* The expected argument is a slice. - -* Note that for slices of bytes, `{=[u8]}` should be preferred as it's better compressed. +`[T] where T: Format` also implements the `Format` trait so it's possible to format `[T]` with `{=?}` but `{=[?]}` uses slightly less bandwidth. -* `[T] where T: Format` also implements the `Format` trait so it's possible to format `[T]` with `{=?}` but `{=[?]}` uses slightly less bandwidth. +> 💡 Note that for slices of bytes, `{=[u8]}` should be preferred as it's better compressed. ## Arrays @@ -39,8 +39,8 @@ struct X { } let xs: [X; 2] = [ -# X { y: 1, z: 2 }, -# X { y: 3, z: 4 }, + # X { y: 1, z: 2 }, + # X { y: 3, z: 4 }, // .. ]; defmt::info!("xs={=[?; 2]}", xs); diff --git a/book/src/format.md b/book/src/format.md index d6fc4407..903ac0a2 100644 --- a/book/src/format.md +++ b/book/src/format.md @@ -1,10 +1,5 @@ # Implementing `Format` -- [`#[derive(Format)]`](#deriveformat) -- [Manual implementation with `write!`](#manual-implementation-with-write) -- [Newtypes](#newtypes) -- [Uncompressed adapters](#uncompressed-adapters) - ## `#[derive(Format)]` The easiest way to implement the `Format` trait for a `struct` or `enum` is to use the `derive` attribute. diff --git a/book/src/global-logger.md b/book/src/global-logger.md index 7949e228..2c6fae08 100644 --- a/book/src/global-logger.md +++ b/book/src/global-logger.md @@ -7,7 +7,7 @@ This is similar to how the `alloc` crate depends on a `#[global_allocator]`. The `global_logger` defines how data is moved from the *device*, where the application runs, to the host, where logs will be formatted and displayed. `global_logger` is transport agnostic: you can use a serial interface, serial over USB, RTT, semihosting, Ethernet, 6LoWPAN, etc. to transfer the data. -The `global_logger` interface comprises the trait `Logger` and the attribute, `#[global_logger]`. +The `global_logger` interface comprises the trait `Logger` and the `#[global_logger]` attribute. ## The `Logger` trait @@ -79,6 +79,7 @@ The other approach uses multiple logging channels: e.g. one for each priority le With this approach logging can be made lock-free: interrupts are not disabled while logging data. This approach requires channel multiplexing in the transport layer. RTT, for example, natively supports multiple channels so this is not an issue, but other transports, like ITM, will require that each log frame to be tagged with the channel it belongs to (e.g. one logging channel = ITM channel). + The trade-offs of using more channels are: - Lock-freedom - higher memory usage on the target, for buffering diff --git a/book/src/hints.md b/book/src/hints.md index b4bb8dc6..79717574 100644 --- a/book/src/hints.md +++ b/book/src/hints.md @@ -47,8 +47,10 @@ Adding `#` in front of a binary and hexadecimal display hints, precedes these nu # extern crate defmt; defmt::info!("{=u8:b}", 42); // -> INFO 101010 defmt::info!("{=u8:#b}", 42); // -> INFO 0b101010 + defmt::info!("{=u8:x}", 42); // -> INFO 2a defmt::info!("{=u8:#x}", 42); // -> INFO 0x2a + defmt::info!("{=u8:X}", 42); // -> INFO 2A defmt::info!("{=u8:#X}", 42); // -> INFO 0x2A ``` @@ -59,9 +61,11 @@ Padding numbers with leading zeros is supported, for example: ``` rust # extern crate defmt; -defmt::info!("{=u8:03}", 42); // -> INFO 042 -defmt::info!("{=u8:08X}", 42); // -> INFO 0000002A -defmt::info!("{=u8:#010X}", 42); // -> INFO 0x0000002A +defmt::info!("{=u8}", 42); // -> INFO 42 +defmt::info!("{=u8:04}", 42); // -> INFO 0042 + +defmt::info!("{=u8:08X}", 42); // -> INFO 0000002A +defmt::info!("{=u8:#08X}", 42); // -> INFO 0x00002A ``` When the alternate form is used for hex and binary, the `0x`/`0b` length is subtracted from the leading zeros. This matches [`core::fmt` behavior](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b11809759f975e266251f7968e542756). diff --git a/book/src/introduction.md b/book/src/introduction.md index e40cf7d0..3b14f9d3 100644 --- a/book/src/introduction.md +++ b/book/src/introduction.md @@ -2,12 +2,12 @@ # `defmt` -`defmt` is a highly efficient logging framework that targets resource-constrained devices, like microcontrollers. +> `defmt` ("de format", short for "deferred formatting") is a highly efficient logging framework that targets resource-constrained devices, like microcontrollers. ## Features - `println!`-like formatting -- Multiple logging levels: error, info, warn, debug, trace +- Multiple logging levels: `error`, `info`, `warn`, `debug`, `trace` - Crate-level logging level filters - Timestamped logs diff --git a/book/src/macros.md b/book/src/macros.md index 57027526..73aea22b 100644 --- a/book/src/macros.md +++ b/book/src/macros.md @@ -3,7 +3,7 @@ > Logging is done using the `error!`, `warn!`, `info!`, `debug!` and `trace!` macros. Each macro logs at the logging level indicated by its name. -The syntax of these macros is roughly the same as the `println`-macro. +The syntax of these macros is roughly the same as the `println!`-macro. ``` rust # extern crate defmt; diff --git a/book/src/panic.md b/book/src/panic.md index 7fbf75b9..f4bc97ac 100644 --- a/book/src/panic.md +++ b/book/src/panic.md @@ -35,7 +35,7 @@ fn defmt_panic() -> ! { If you are using the `panic-probe` crate then you should "abort" (call `cortex_m::asm::udf`) from `#[defmt::panic_handler]` to match its behavior. -Even if you don't run into the "double panic message printed" issue you may still want to use `#[defmt::panic_handler]` because this way `defmt::panic` and `defmt::assert` will *not* go through the `core::panic` machinery and that *may* reduce code size (we recommend you measure the effect of the change). +> 💡 Even if you don't run into the "double panic message printed" issue you may still want to use `#[defmt::panic_handler]` because this way `defmt::panic` and `defmt::assert` will *not* go through the `core::panic` machinery and that *may* reduce code size (we recommend you measure the effect of the change). > ⚠️ The `#[panic_handler]` attribute cannot be used together with the `export_name` or `no_mangle` attributes diff --git a/book/src/printers.md b/book/src/printers.md index a891f4c9..0d0fd51a 100644 --- a/book/src/printers.md +++ b/book/src/printers.md @@ -4,10 +4,10 @@ The following printers are currently available: - [`probe-run`], parses data sent over RTT (ARM Cortex-M only). - - ℹ️ If you are using the git version of defmt, make sure you also install the tool from git and not crates.io. + > 💡 If you are using the git version of defmt, make sure you also install the tool from git and not crates.io. - [`defmt-print`], a generic command-line tool that decodes defmt data passed into its standard input. - [`qemu-run`], parses data sent by QEMU over semihosting (ARM Cortex-M only). - - ℹ️ Used for internal testing and won't be published to crates.io + > 💡 Used for internal testing and won't be published to crates.io [`probe-run`]: https://github.com/knurling-rs/probe-run [`defmt-print`]: https://github.com/knurling-rs/defmt/tree/main/print From 0d054d87488864051cdb4283a544e4353fe3299d Mon Sep 17 00:00:00 2001 From: Johann Hemmann Date: Tue, 13 Jul 2021 22:07:39 +0200 Subject: [PATCH 4/5] Another read-through in "Files changed" --- book/src/setup-app.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/book/src/setup-app.md b/book/src/setup-app.md index 13930caf..3c5ce65c 100644 --- a/book/src/setup-app.md +++ b/book/src/setup-app.md @@ -1,5 +1,7 @@ # Application setup +> ⚠️ Remember to also do the base setup from the previous chapter! + ## Linker script The application must be linked using a custom linking process that includes the `defmt.x` linker script. From c38b98de4ee8cb499ea550546bae1d61b53f77ce Mon Sep 17 00:00:00 2001 From: Johann Hemmann Date: Fri, 16 Jul 2021 00:01:18 +0200 Subject: [PATCH 5/5] Address `japaric`s review comments --- book/src/bitfields.md | 2 -- book/src/global-logger.md | 4 ++-- book/src/macros.md | 6 +++--- book/src/primitives.md | 2 +- book/src/setup-app.md | 8 +++----- book/src/setup.md | 2 +- 6 files changed, 10 insertions(+), 14 deletions(-) diff --git a/book/src/bitfields.md b/book/src/bitfields.md index 22d03f28..b5a96f67 100644 --- a/book/src/bitfields.md +++ b/book/src/bitfields.md @@ -5,8 +5,6 @@ The bitfield argument is expected to be a *unsigned* integer that's large enough to contain the bitfields. For example, if bitfield ranges only cover up to bit `11` (e.g. `=8..12`) then the argument must be at least `u16`. -Bit indices are little-endian: the 0th bit is the rightmost bit. - When paired with a positional parameter it can be used to display the bitfields of a register. ``` rust # extern crate defmt; diff --git a/book/src/global-logger.md b/book/src/global-logger.md index 2c6fae08..48d6e548 100644 --- a/book/src/global-logger.md +++ b/book/src/global-logger.md @@ -11,7 +11,7 @@ The `global_logger` interface comprises the trait `Logger` and the `#[global_log ## The `Logger` trait -Firstly `Logger` specifies how to acquire and release a handle to a global logger, as well as how the data is put on the wire. +`Logger` specifies how to acquire and release a handle to a global logger, as well as how the data is put on the wire. ```rust # extern crate defmt; @@ -39,7 +39,7 @@ See the API documentation for more details about the safety requirements of the ## The `#[global_logger]` attribute -Secondly, `#[global_logger]` specifies which `Logger` implementation will be used by the application. +`#[global_logger]` specifies which `Logger` implementation will be used by the application. `#[global_logger]` must be used on a *unit* struct, a struct with no fields, which must implement the `Logger` trait. It's recommended that this struct is kept private. diff --git a/book/src/macros.md b/book/src/macros.md index 73aea22b..2c53a50f 100644 --- a/book/src/macros.md +++ b/book/src/macros.md @@ -32,15 +32,15 @@ defmt::trace!("{}", x); ## Type and display hints -The `defmt` grammer is similar to `core::fmt`, but not the same. It works like following: +The `defmt` grammar is similar to `core::fmt`, but not the same. The syntax of a formatting parameter is shown below: > `{[pos][=Type][:Display]}` ### Type hint The `Type` hint always starts with a `=`. -For once it enables the framework to further compress the logs resulting in higher throughput. -Secondly it also typechecks the supplied value to fit the specified type. +For one it enables the framework to further compress the logs resulting in higher throughput. +Secondly it also typechecks the supplied value to fit the specified type and possibly coerces the value into the specified type. The type hint can be a [primitive](./primitives.md) or [one](./format-slices.md), [of](./istr.md), [the](./bitfields.md) special types. Read on to learn more about the type hints. diff --git a/book/src/primitives.md b/book/src/primitives.md index fe22147d..5390cf9e 100644 --- a/book/src/primitives.md +++ b/book/src/primitives.md @@ -1,6 +1,6 @@ # Primitives -Following **primitive types** are available: +The following **primitive types** are available: | type hint | name | | :------------------- | :---------------------------------- | diff --git a/book/src/setup-app.md b/book/src/setup-app.md index 3c5ce65c..665592cf 100644 --- a/book/src/setup-app.md +++ b/book/src/setup-app.md @@ -15,12 +15,10 @@ To pass `defmt.x` to the linker add the `-C link-arg=-Tdefmt.x` flag to the rust rustflags = [ # --- KEEP existing `link-arg` flags --- "-C", "link-arg=-Tlink.x", + "-C", "link-arg=--nmagic", - # --- ADD following new flags --- + # --- ADD following new flag --- "-C", "link-arg=-Tdefmt.x", - # This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x - # See https://github.com/rust-embedded/cortex-m-quickstart/pull/95 - "-C", "link-arg=--nmagic", ] ``` @@ -37,7 +35,7 @@ The following `global_logger`s are provided as part of the project: - [`defmt-semihosting`], logs over semihosting. Meant only for testing `defmt` on a virtual Cortex-M device (QEMU). [`defmt-rtt`]: https://docs.rs/defmt-rtt/ -[`defmt-itm`]: https://docs.rs/defmt-rtt/ +[`defmt-itm`]: https://docs.rs/defmt-itm/ [`defmt-semihosting`]: https://github.com/knurling-rs/defmt/tree/6cfd947384debb18a4df761cbe454f8d86cf3441/firmware/defmt-semihosting Information about how to write a `global_logger` can be found in the [`#[global_logger]` section](./global-logger.md). diff --git a/book/src/setup.md b/book/src/setup.md index 1d6bbc69..ab105e83 100644 --- a/book/src/setup.md +++ b/book/src/setup.md @@ -33,4 +33,4 @@ defmt-error = [] --- That is already it for setting up `defmt` for your library! -See the next chapter for additional steps for applications. +Continue to the [next page](setup-app.md) for additional steps for applications.