Benedikt ca04263b7b
RMT: Make PulseCode a newtype rather than an extension trait (#3884)
* RMT: make PulseCode a newtype rather than an extension trait on u32

This has several advantages:
- the meaning of `u32` used as pulse code becomes more explicit
- it allows using `PulseCode` methods in `const` context (which is otherwise
  not possible because Rust does not presently support associated const
  fn in traits).
- it allows providing custom `defmt::Format` and `core::fmt::Debug` impls
  for `PulseCode`, greatly helping with debugging

I have taken the liberty to implement `core::fmt::Debug` in a slightly
non-standard way: The most natural implementation would probably use a
struct-style output like

  PulseCode { length1: 42, level1: Level::High, length2: 24, level2: Level::Low }

However, that is very lengthy and not really human-readable anymore when
dealing with an array of `PulseCode`s. Thus, this uses the more compact format

  PulseCode(H 42, L 24)

This provides `u32: From<PulseCode>` and `PulseCode: From<u32>` impls and
converts rx and tx methods to accept `impl Into<PulseCode>` and
`impl From<PulseCode>`, respectively.
This should help to reduce how much user code needs to change (but replacing
`u32` type annotations with `PulseCode` will be required).

By applying `#[repr(transparent)]` to `struct PulseCode`, it is
guaranteed to match the layout of `u32` such that accessing the hardware
buffer via `*mut PulseCode` pointers is valid.

* RMT: Address review on PulseCode refactor, further refine the interface a bit

- introduce Level::const_from and Level::const_into
- pre-compute a few more shifts and masks (this is unlikely to affect
  generated code, since the compiler would have const propagated them
  anyway, but it helps to keep the PulseCode impl more readable)
- improve docstrings
- remove PulseCode::empty in favor of PulseCode::default, keep
  PulseCode::end_marker for now (but it's not completely clear that this
  interface is optimal; see also the FIXME note on adding a variant of
  this methods that supports settings levels and length1)
- make PulseCode::new_unchecked pub and shuffle it around in the code so
  that it doesn't show up first in the docs
- factor out PulseCode::symbolX methods for internal use in debug
  formatting
- sprinkle a few more #[inline] to be totally sure that this really adds
  no overhead over having plain u32
- convert methods receivers from &self to self given that PulseCode is
  Copy (which probably doesn't matter much since all these methods
  should always be inlined)
- remove PulseCode::as_u32() and make the tuple field pub: There's no
  safety implication of marking this pub, and field access still
  provides a const-compatible way to obtain the wrapped value
2025-08-08 07:51:49 +00:00
..

Examples

This package contains a number of binary applications demonstrating the use of various hardware peripherals found within ESP32 the family of devices.

Each device has its own unique set of peripherals, and as such not every example will run on every device. We recommend building and flashing the examples using the xtask method documented below, which will greatly simplify the process.

To check if a device is compatible with a given example, check the metadata comments above the imports, which will list all supported devices following the //% CHIPS: designator. If this metadata is not present, then the example will work on any device supported by esp-hal.

As previously stated, we use the cargo-xtask pattern for automation. Commands invoking this tool must be run from the root of the repository.

Building Examples

You can build all examples for a given device using the build examples subcommand:

cargo xtask build examples esp-hal esp32

Note that we must specify which package to build the examples for, since this repository contains multiple packages (specifying esp-hal will build the examples in the examples package instead).

Running Examples

You can also build and then subsequently flash and run an example using the run example subcommand. With a target device connected to your host system, run:

cargo xtask run example esp-hal esp32c6 --example embassy_hello_world

Again, note that we must specify which package to build the example from, plus which example to build and flash to the target device.

Adding Examples

If you are contributing to esp-hal and would like to add an example, the process is generally the same as any other project.

One major difference in our case is the metadata comments which state the compatible devices and required features for an example. Both of these designators are optional; if //% CHIPS: is omitted then all devices considered to be supported, and if //% FEATURES: is omitted then no features are enabled at build time.

To demonstrated, in src/bin/embassy_hello_world.rs you will see the following:

//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% FEATURES: embassy esp-hal-embassy/integrated-timers

Another thing to be aware of is the GPIO pins being used. We have tried to use pins available the DevKit-C boards from Espressif, however this is being done on a best-effort basis.

In general, the following GPIO are recommended for use, though be conscious of whether certain pins are used for UART, strapping pins, etc. on some devices:

  • GPIO0
  • GPIO1
  • GPIO2
  • GPIO3
  • GPIO4
  • GPIO5
  • GPIO8
  • GPIO9
  • GPIO10