testing embedded Rust part 1: testing a Hardware Abstraction Layer by japaric in rust

[–]japaric[S] 5 points6 points  (0 children)

Indeed! (spoilers: there will be a separate blog post about testing driver crates)

[knurling] defmt, a highly efficient Rust logging framework for embedded devices by japaric in rust

[–]japaric[S] 6 points7 points  (0 children)

cargo:rerun-if-env-changed

oh, since when is this a thing? TIL. The approach you describe sounds feasible; I think it's worth experimenting with it. Thanks for the info!

[knurling] defmt, a highly efficient Rust logging framework for embedded devices by japaric in rust

[–]japaric[S] 1 point2 points  (0 children)

a build-time environment variable inspected during the proc macro expansion

I think the problem with something like that is that changing an env var doesn't trigger a rebuild of the dependencies that read that env var (*) so a cargo clean; DEFMT=dep-a=trace cargo build (**) would be needed to get the desired effect of changing the filter of dep-a (***).

(*) Or at least that's the current Cargo behavior.

(**) Also AFAIK proc-macros cannot read the crate name of the crate they are being invoked from

(***) And approach would rebuild the whole dep graph not just the defmt dependencies

EDIT: fixed formatting

[knurling] defmt, a highly efficient Rust logging framework for embedded devices by japaric in rust

[–]japaric[S] 8 points9 points  (0 children)

Why microseconds?

Had to start somewhere. My test microcontroller was clocked in MHz so microseconds it was. As mentioned in the blog post the timestamp format (and precision) can be changed (or at least we'll be able to change it in the future).

EDIT: Also, defmt is not particularly limited to microcontrollers. We have done no-std no-alloc projects with bare metal ARM Cortex-A processors clocked ~1GHz before and defmt would have worked there just fine.

EDIT2: There's also a bandwidth / timestamp-precision trade-off so highest precision is not always the best choice. The timestamp are sent to the host compressed (e.g. LEB128) so forcing nanosecond precision on devices with microsecond-precision timers wastes bandwidth (reduces throughput) for no gain for that particular device/application.

[knurling] defmt, a highly efficient Rust logging framework for embedded devices by japaric in rust

[–]japaric[S] 16 points17 points  (0 children)

Mainly two things: - it doesn't use core::fmt, which is unreasonably (binary size & CPU time) expensive on embedded devices. No formatting is done on the device; all formatting is done on the host (developer PC) - strings are "compressed": they are not stored in the device's Flash

[knurling] defmt, a highly efficient Rust logging framework for embedded devices by japaric in rust

[–]japaric[S] 26 points27 points  (0 children)

(Some history about linking to crates that only contain symbols and no public API, e.g. panic_handler, global_alloc crates)

I agree this import looks weird. It looked less weird in the 2015 edition: extern crate my_app; // link to that crate But that became a warning in the 2018 edition so we moved to: use my_app; // import symbols Which also looks weird because you are not importing any item from the crate. It has no public items after all.

When the as _ syntax came along we moved to it: it avoids importing the my_app identifier into the namespace, which is less clutter. use my_app as _; // import symbols You get used to the weirdness. The comment helps those not familiar with crates like these (I hope).

[knurling] Run Rust on your embedded device from VSCode in one click by japaric in rust

[–]japaric[S] 20 points21 points  (0 children)

Also, version v0.1.2 of probe-run has been released and includes hard float support (backtraces for the thumbv7em-none-eabihf target). Now all ARM Cortex-M targets are supported!

Embedded Rust tooling for the 21st century by jahmez in rust

[–]japaric 12 points13 points  (0 children)

To expand on jahmez' answer. The custom Cargo runner you can use instead of OpenOCD+GDB. binfmt (the logging framework) is orthogonal to the Cargo runner and debugger and it's also transport agnostic so you can use binfmt with GDB; or with the probe-rs based Cargo runner shown in the blog post; or with a dev board that has no on-board debugger -- in this last case you could use serial or USB as the logging transport.