From 2cc7a8ccbde4137050b28b27e4335683415ef6d1 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 21 Mar 2024 13:41:46 +0000 Subject: [PATCH 01/16] document usb port differences and recommend usb_serial_jtag example (#1321) --- examples/src/bin/hello_world.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/src/bin/hello_world.rs b/examples/src/bin/hello_world.rs index da503d77ace..0846c260cca 100644 --- a/examples/src/bin/hello_world.rs +++ b/examples/src/bin/hello_world.rs @@ -1,7 +1,10 @@ //! This shows how to write text to UART0. //! //! You can see the output with `espflash` if you provide the `--monitor` -//! option. +//! option. Depending on the chip, you will need to ensure that you are +//! connected to the UART USB port, and not the USB-SERIAL-JTAG port. +//! If you want to test printing over USB-SERIAL-JTAG, try the usb_serial_jtag +//! example instead. //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 //% FEATURES: embedded-hal-02 From 1444b627772aa2ffcc2b3c18e972afcc5222a354 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 21 Mar 2024 13:46:49 +0000 Subject: [PATCH 02/16] ensure we don't strongly define cpu int handlers (#1324) --- esp-hal/ld/riscv/hal-defaults.x | 62 ++++++++++++++++----------------- esp-riscv-rt/src/lib.rs | 33 ------------------ 2 files changed, 31 insertions(+), 64 deletions(-) diff --git a/esp-hal/ld/riscv/hal-defaults.x b/esp-hal/ld/riscv/hal-defaults.x index 133577f3958..1d845d3e6da 100644 --- a/esp-hal/ld/riscv/hal-defaults.x +++ b/esp-hal/ld/riscv/hal-defaults.x @@ -1,35 +1,35 @@ PROVIDE(DefaultHandler = EspDefaultHandler); -PROVIDE(interrupt1 = DefaultHandler); -PROVIDE(interrupt2 = DefaultHandler); -PROVIDE(interrupt3 = DefaultHandler); -PROVIDE(interrupt4 = DefaultHandler); -PROVIDE(interrupt5 = DefaultHandler); -PROVIDE(interrupt6 = DefaultHandler); -PROVIDE(interrupt7 = DefaultHandler); -PROVIDE(interrupt8 = DefaultHandler); -PROVIDE(interrupt9 = DefaultHandler); -PROVIDE(interrupt10 = DefaultHandler); -PROVIDE(interrupt11 = DefaultHandler); -PROVIDE(interrupt12 = DefaultHandler); -PROVIDE(interrupt13 = DefaultHandler); -PROVIDE(interrupt14 = DefaultHandler); -PROVIDE(interrupt15 = DefaultHandler); -PROVIDE(interrupt16 = DefaultHandler); -PROVIDE(interrupt17 = DefaultHandler); -PROVIDE(interrupt18 = DefaultHandler); -PROVIDE(interrupt19 = DefaultHandler); -PROVIDE(interrupt20 = DefaultHandler); -PROVIDE(interrupt21 = DefaultHandler); -PROVIDE(interrupt22 = DefaultHandler); -PROVIDE(interrupt23 = DefaultHandler); -PROVIDE(interrupt24 = DefaultHandler); -PROVIDE(interrupt25 = DefaultHandler); -PROVIDE(interrupt26 = DefaultHandler); -PROVIDE(interrupt27 = DefaultHandler); -PROVIDE(interrupt28 = DefaultHandler); -PROVIDE(interrupt29 = DefaultHandler); -PROVIDE(interrupt30 = DefaultHandler); -PROVIDE(interrupt31 = DefaultHandler); +PROVIDE(cpu_int_1_handler = DefaultHandler); +PROVIDE(cpu_int_2_handler = DefaultHandler); +PROVIDE(cpu_int_3_handler = DefaultHandler); +PROVIDE(cpu_int_4_handler = DefaultHandler); +PROVIDE(cpu_int_5_handler = DefaultHandler); +PROVIDE(cpu_int_6_handler = DefaultHandler); +PROVIDE(cpu_int_7_handler = DefaultHandler); +PROVIDE(cpu_int_8_handler = DefaultHandler); +PROVIDE(cpu_int_9_handler = DefaultHandler); +PROVIDE(cpu_int_10_handler = DefaultHandler); +PROVIDE(cpu_int_11_handler = DefaultHandler); +PROVIDE(cpu_int_12_handler = DefaultHandler); +PROVIDE(cpu_int_13_handler = DefaultHandler); +PROVIDE(cpu_int_14_handler = DefaultHandler); +PROVIDE(cpu_int_15_handler = DefaultHandler); +PROVIDE(cpu_int_16_handler = DefaultHandler); +PROVIDE(cpu_int_17_handler = DefaultHandler); +PROVIDE(cpu_int_18_handler = DefaultHandler); +PROVIDE(cpu_int_19_handler = DefaultHandler); +PROVIDE(cpu_int_20_handler = DefaultHandler); +PROVIDE(cpu_int_21_handler = DefaultHandler); +PROVIDE(cpu_int_22_handler = DefaultHandler); +PROVIDE(cpu_int_23_handler = DefaultHandler); +PROVIDE(cpu_int_24_handler = DefaultHandler); +PROVIDE(cpu_int_25_handler = DefaultHandler); +PROVIDE(cpu_int_26_handler = DefaultHandler); +PROVIDE(cpu_int_27_handler = DefaultHandler); +PROVIDE(cpu_int_28_handler = DefaultHandler); +PROVIDE(cpu_int_29_handler = DefaultHandler); +PROVIDE(cpu_int_30_handler = DefaultHandler); +PROVIDE(cpu_int_31_handler = DefaultHandler); INCLUDE "device.x" diff --git a/esp-riscv-rt/src/lib.rs b/esp-riscv-rt/src/lib.rs index 226492c3e49..d9d14019711 100644 --- a/esp-riscv-rt/src/lib.rs +++ b/esp-riscv-rt/src/lib.rs @@ -860,38 +860,5 @@ r#" .weak cpu_int_29_handler .weak cpu_int_30_handler .weak cpu_int_31_handler -cpu_int_1_handler: -cpu_int_2_handler: -cpu_int_3_handler: -cpu_int_4_handler: -cpu_int_5_handler: -cpu_int_6_handler: -cpu_int_7_handler: -cpu_int_8_handler: -cpu_int_9_handler: -cpu_int_10_handler: -cpu_int_11_handler: -cpu_int_12_handler: -cpu_int_13_handler: -cpu_int_14_handler: -cpu_int_15_handler: -cpu_int_16_handler: -cpu_int_17_handler: -cpu_int_18_handler: -cpu_int_19_handler: -cpu_int_20_handler: -cpu_int_21_handler: -cpu_int_22_handler: -cpu_int_23_handler: -cpu_int_24_handler: -cpu_int_25_handler: -cpu_int_26_handler: -cpu_int_27_handler: -cpu_int_28_handler: -cpu_int_29_handler: -cpu_int_30_handler: -cpu_int_31_handler: - la ra, abort #abort since proper handler is not defined, this could also just load the default _start_trap_rust_hal address and let the hal handle it. - jr ra "#, } From baea915935a7311af17cbed12fe323c6b5e08eb6 Mon Sep 17 00:00:00 2001 From: Sergio Gasquez Arcos Date: Thu, 21 Mar 2024 15:28:27 +0100 Subject: [PATCH 03/16] Add HIL testing (#1297) * Create the `hil-test` package * Add a simple integration test to verify basic GPIO functionality * WIP * feat: Update with esp-hal unification * build: Update dependencies * feat: Add a simple CI workflow test * ci: Avoid using a gh-hosted-runner to build * ci: Remove building bins in gh-hosted-runner * ci: Remove HIL Gpio CI test * ci: Test all the available tests * test: Add spi_full_duplex test * docs: Add documentation * test: Add uart test * style: Remove unused imports * docs: Update wiring, document H2 VM * ci: Enable H2 tests * ci: Add rust-cache action * docs: Document H2 vm * test: Add timeout * ci: Enable ESP32-C3 tests * feat: Add timeouts * feat: Add aes test * ci: Avoid running CI workflow when we change hil-test stuff * test: Remove warnings * feat: Address feedback * feat: Update features names and spi methods * ci: Remove rust-cache action * Update HIL to probe-rs#2292 (#1307) * feat: Update probe-rs/embedded-test to probe-rs#2292 * feat: Remove lib * ci: Use a matrix * ci: Enable ESP32C3 * feat: Add a way to cfg away test for unsuported peripherals * ci: Update trigger conditions * feat: Update pins to make it work on s3 * feat: Changes enabling S3 * feat: Remove log feature * feat: Adapt for rebase * feat: Remove env * feat: enable S3 * chore: Remove todo * build: Pin dependencies * feat: Add target alias * docs: Update readme * fix: Fix traits imports after rebase. Use debug * build: Remove lto * feat: Build tests on release mode --------- Co-authored-by: Jesse Braham --- .github/workflows/ci.yml | 2 + .github/workflows/hil.yml | 59 +++++++++++++++ Cargo.toml | 1 + hil-test/.cargo/config.toml | 29 ++++++++ hil-test/Cargo.toml | 93 ++++++++++++++++++++++++ hil-test/README.md | 95 ++++++++++++++++++++++++ hil-test/tests/aes.rs | 99 +++++++++++++++++++++++++ hil-test/tests/gpio.rs | 72 +++++++++++++++++++ hil-test/tests/spi_full_duplex.rs | 115 ++++++++++++++++++++++++++++++ hil-test/tests/uart.rs | 73 +++++++++++++++++++ 10 files changed, 638 insertions(+) create mode 100644 .github/workflows/hil.yml create mode 100644 hil-test/.cargo/config.toml create mode 100644 hil-test/Cargo.toml create mode 100644 hil-test/README.md create mode 100644 hil-test/tests/aes.rs create mode 100644 hil-test/tests/gpio.rs create mode 100644 hil-test/tests/spi_full_duplex.rs create mode 100644 hil-test/tests/uart.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3676eb1379..f5dc050c325 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,12 +18,14 @@ on: paths-ignore: - "**/CHANGELOG.md" - "**/README.md" + - "**/hil-test/**" push: branches-ignore: - "gh-readonly-queue/**" paths-ignore: - "**/CHANGELOG.md" - "**/README.md" + - "**/hil-test/**" merge_group: workflow_dispatch: diff --git a/.github/workflows/hil.yml b/.github/workflows/hil.yml new file mode 100644 index 00000000000..79bbe6f4471 --- /dev/null +++ b/.github/workflows/hil.yml @@ -0,0 +1,59 @@ +name: HIL + +on: + merge_group: + workflow_dispatch: + inputs: + repository: + description: "Owner and repository to test" + required: true + default: 'esp-rs/esp-hal' + branch: + description: "Branch, tag or SHA to checkout." + required: true + default: "main" + +env: + CARGO_TERM_COLOR: always + +jobs: + # Test RISC-V targets: + riscv-hil: + name: HIL Test | ${{ matrix.target.soc }} + runs-on: + labels: [self-hosted, "${{ matrix.target.runner }}"] + strategy: + fail-fast: false + matrix: + target: + - soc: esp32c3 + runner: rustboard + rust-target: riscv32imc-unknown-none-elf + - soc: esp32c6 + runner: esp32c6-usb + rust-target: riscv32imac-unknown-none-elf + - soc: esp32h2 + runner: esp32h2-usb + rust-target: riscv32imac-unknown-none-elf + steps: + - uses: actions/checkout@v4 + if: github.event_name != 'workflow_dispatch' + + - uses: actions/checkout@v4 + if: github.event_name == 'workflow_dispatch' + with: + repository: ${{ github.event.inputs.repository }} + ref: ${{ github.event.inputs.branch }} + + - uses: dtolnay/rust-toolchain@v1 + with: + target: ${{ matrix.target.rust-target }} + toolchain: nightly + components: rust-src + + - name: Run tests + working-directory: hil-test + run: cargo ${{ matrix.target.soc }} + + # Test Xtensa targets: + # TODO: Add jobs for Xtensa once supported by `probe-rs` diff --git a/Cargo.toml b/Cargo.toml index 6215f581191..b86194ea725 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,5 @@ exclude = [ "esp-metadata", "esp-riscv-rt", "examples", + "hil-test", ] diff --git a/hil-test/.cargo/config.toml b/hil-test/.cargo/config.toml new file mode 100644 index 00000000000..49e46b3500d --- /dev/null +++ b/hil-test/.cargo/config.toml @@ -0,0 +1,29 @@ +[alias] +# esp32 = "test --release --features=esp32 --target=xtensa-esp32-none-elf -- --chip esp32-3.3v" +# esp32c2 = "test --release --features=esp32c2 --target=riscv32imc-unknown-none-elf -- --chip esp32c2" +esp32c3 = "test --release --features=esp32c3 --target=riscv32imc-unknown-none-elf -- --chip esp32c3" +esp32c6 = "test --release --features=esp32c6 --target=riscv32imac-unknown-none-elf -- --chip esp32c6" +esp32h2 = "test --release --features=esp32h2 --target=riscv32imac-unknown-none-elf -- --chip esp32h2" +# esp32p4 = "test --release --features=esp32p4 --target=riscv32imafc-unknown-none-elf -- --chip esp32p4" +# esp32s2 = "test --release --features=esp32s2 --target=xtensa-esp32s2-none-elf -- --chip esp32s2" +esp32s3 = "test --release --features=esp32s3 --target=xtensa-esp32s3-none-elf -- --chip esp32s3" + +[target.'cfg(target_arch = "riscv32")'] +runner = "probe-rs run" +rustflags = [ + "-C", "link-arg=-Tlinkall.x", + "-C", "link-arg=-Tembedded-test.x", + "-C", "link-arg=-Tdefmt.x", +] + +[target.'cfg(target_arch = "xtensa")'] +runner = "probe-rs run" +rustflags = [ + "-C", "link-arg=-nostartfiles", + "-C", "link-arg=-Wl,-Tlinkall.x", + "-C", "link-arg=-Tdefmt.x", + "-C", "link-arg=-Tembedded-test.x", +] + +[unstable] +build-std = ["core"] diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml new file mode 100644 index 00000000000..dd1f5a5dde2 --- /dev/null +++ b/hil-test/Cargo.toml @@ -0,0 +1,93 @@ +[package] +name = "hil-test" +version = "0.0.0" +edition = "2021" +publish = false + +[[test]] +name = "aes" +harness = false + +[[test]] +name = "gpio" +harness = false + +[[test]] +name = "spi_full_duplex" +harness = false + +[[test]] +name = "uart" +harness = false + +[dependencies] +defmt = { version = "0.3.5" } +defmt-rtt = { version = "0.4.0" } +esp-hal = { path = "../esp-hal", features = ["embedded-hal", "embedded-hal-02", "defmt"], optional = true } +embedded-hal-02 = { version = "0.2.7", package = "embedded-hal", features = ["unproven"] } +embedded-hal-async = { version = "1.0.0", optional = true } +embedded-hal = { version = "1.0.0" } +embedded-hal-nb = { version = "1.0.0", optional = true } +embassy-executor = { default-features = false, version = "0.5.0", features = ["executor-thread", "arch-riscv32"], optional = true } +semihosting = "0.1.6" + +[dev-dependencies] +# Add the `embedded-test/defmt` feature for more verbose testing +embedded-test = {git = "https://github.com/probe-rs/embedded-test", rev = "8e3f925"} + +[features] +# Device support (required!): +esp32 = ["esp-hal/esp32"] +esp32c2 = ["esp-hal/esp32c2"] +esp32c3 = ["esp-hal/esp32c3"] +esp32c6 = ["esp-hal/esp32c6"] +esp32h2 = ["esp-hal/esp32h2"] +esp32s2 = ["esp-hal/esp32s2"] +esp32s3 = ["esp-hal/esp32s3"] +# Async & Embassy: +async = ["dep:embedded-hal-async", "esp-hal?/async"] +embassy = ["esp-hal?/embassy", "embedded-test/embassy", "dep:embassy-executor"] +embassy-executor-interrupt = ["esp-hal?/embassy-executor-interrupt"] +embassy-executor-thread = ["esp-hal?/embassy-executor-thread"] +embassy-time-systick-16mhz = ["esp-hal?/embassy-time-systick-16mhz"] +embassy-time-systick-80mhz = ["esp-hal?/embassy-time-systick-80mhz"] +embassy-time-timg0 = ["esp-hal?/embassy-time-timg0"] + +# cargo build/run +[profile.dev] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 'z' # <- +overflow-checks = true # <- + +# cargo test +[profile.test] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo build/run --release +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +opt-level = 3 # <- +overflow-checks = false # <- + +# cargo test --release +[profile.bench] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +opt-level = 3 # <- +overflow-checks = false # <- + +[patch.crates-io] +semihosting = { git = "https://github.com/taiki-e/semihosting", rev = "c829c19" } diff --git a/hil-test/README.md b/hil-test/README.md new file mode 100644 index 00000000000..6a04bc0bb49 --- /dev/null +++ b/hil-test/README.md @@ -0,0 +1,95 @@ +# hil-test + +Hardware-in-loop testing for `esp-hal`. + +For assistance with this package please [open an issue] or [start a discussion]. + +[open an issue]: https://github.com/esp-rs/esp-hal/issues/new +[start a discussion]: https://github.com/esp-rs/esp-hal/discussions/new/choose + +## Quickstart + +We use [embedded-test] as our testing framework, which relies on [defmt] internally. This allows us to write unit and integration tests much in the same way you would for a normal Rust project, when the standard library is available, and to execute them using Cargo's built-in test runner. + +[embedded-test]: https://github.com/probe-rs/embedded-test +[defmt]: https://github.com/knurling-rs/defmt + +### Running Tests Locally + +We use [probe-rs] for flashing and running the tests on a target device, however, this **MUST** be installed from the correct revision, and with the correct features enabled: + +```text +cargo install probe-rs \ + --git=https://github.com/probe-rs/probe-rs \ + --rev=b431b24 \ + --features=cli \ + --bin=probe-rs +``` + +Target device **MUST** connected via its USB-Serial-JTAG port, or if unavailable (eg. ESP32, ESP32-C2, ESP32-S2) then you must connect a compatible debug probe such as an [ESP-Prog]. + +You can run all test for a given device using: + +```shell +cargo +nightly esp32c6 +# or +cargo +esp esp32s3 +``` + +For running a single test on a target: + +```shell +# Run GPIO tests for ESP32-C6 +CARGO_BUILD_TARGET=riscv32imac-unknown-none-elf \ +PROBE_RS_CHIP=esp32c6 \ + cargo +nightly test --features=esp32c6 --test=gpio +``` +- If the `--test` argument is omitted, then all tests will be run. +- The build target **MUST** be specified via the `CARGO_BUILD_TARGET` environment variable or as an argument (`--target`). +- The chip **MUST** be specified via the `PROBE_RS_CHIP` environment variable or as an argument of `probe-rs` (`--chip`). + +Some tests will require physical connections, please see the current [configuration in our runners](#running-tests-remotes-ie-on-self-hosted-runners). + +### Running Tests Remotes (ie. On Self-Hosted Runners) +The [`hil.yml`] workflow builds the test suite for all our available targets and executes them. + +Our Virtual Machines have the following setup: +- ESP32-C3 (`rustboard`): + - Devkit: `ESP32-C3-DevKit-RUST-1` connected via USB-Serial-JTAG. + - `GPIO2` and `GPIO4` are connected. + - VM: Configured with the following [setup](#vm-setup) +- ESP32-C6 (`esp32c6-usb`): + - Devkit: `ESP32-C6-DevKitC-1 V1.2` connected via USB-Serial-JTAG (`USB` port). + - `GPIO2` and `GPIO4` are connected. + - VM: Configured with the following [setup](#vm-setup) +- ESP32-H2 (`esp32h2-usb`): + - Devkit: `ESP32-H2-DevKitM-1` connected via USB-Serial-JTAG (`USB` port). + - `GPIO2` and `GPIO4` are connected. + - VM: Configured with the following [setup](#vm-setup) + +[`hil.yml`]: https://github.com/esp-rs/esp-hal/blob/main/.github/workflows/hil.yml + +#### VM Setup +```bash +# Install Rust: +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain stable -y --profile minimal +# Source the current shell: +source "$HOME/.cargo/env" +# Install dependencies +sudo apt install -y pkg-config libudev-dev +# Install probe-rs +cargo install probe-rs --git=https://github.com/probe-rs/probe-rs --rev=b431b24 --features=cli --bin=probe-rs --locked --force +# Add the udev rules +wget -O - https://probe.rs/files/69-probe-rs.rules | sudo tee /etc/udev/rules.d/69-probe-rs.rules > /dev/null +# Add the user to plugdev group +sudo usermod -a -G plugdev $USER +# Reboot the VM +``` + +## Adding New Tests + +1. Create a new integration test file (`tests/$PERIPHERAL.rs`) +2. Add a corresponding `[[test]]` entry to `Cargol.toml` (**MUST** set `harness = false`) +3. Write the tests +4. Document any necessary physical connections on boards connected to self-hosted runners +5. Write some documentation at the top of the `tests/$PERIPHERAL.rs` file with the pins being used and the required connections, if applicable. diff --git a/hil-test/tests/aes.rs b/hil-test/tests/aes.rs new file mode 100644 index 00000000000..950453a574a --- /dev/null +++ b/hil-test/tests/aes.rs @@ -0,0 +1,99 @@ +//! AES Test + +#![no_std] +#![no_main] + +use defmt_rtt as _; +use esp_hal::{ + aes::{Aes, Mode}, + peripherals::Peripherals, +}; + +struct Context<'a> { + aes: Aes<'a>, +} + +impl Context<'_> { + pub fn init() -> Self { + let peripherals = Peripherals::take(); + let aes = Aes::new(peripherals.AES); + + Context { aes } + } +} + +#[cfg(not(any( + feature = "esp32c3", + feature = "esp32c6", + feature = "esp32h2", + feature = "esp32s3" +)))] +mod not_test { + #[esp_hal::entry] + fn main() -> ! { + semihosting::process::exit(0) + } + #[panic_handler] + fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} + } +} + +#[cfg(test)] +#[cfg(any( + feature = "esp32c3", + feature = "esp32c6", + feature = "esp32h2", + feature = "esp32s3" +))] +#[embedded_test::tests] +mod tests { + use defmt::assert_eq; + + use super::*; + + #[init] + fn init() -> Context<'static> { + Context::init() + } + + #[test] + fn test_aes_encryption(mut ctx: Context<'static>) { + let keytext = "SUp4SeCp@sSw0rd".as_bytes(); + let plaintext = "message".as_bytes(); + let encrypted_message = [ + 0xb3, 0xc8, 0xd2, 0x3b, 0xa7, 0x36, 0x5f, 0x18, 0x61, 0x70, 0x0, 0x3e, 0xd9, 0x3a, + 0x31, 0x96, + ]; + + // create an array with aes128 key size + let mut keybuf = [0_u8; 16]; + keybuf[..keytext.len()].copy_from_slice(keytext); + + // create an array with aes block size + let mut block_buf = [0_u8; 16]; + block_buf[..plaintext.len()].copy_from_slice(plaintext); + + let mut block = block_buf.clone(); + ctx.aes.process(&mut block, Mode::Encryption128, &keybuf); + assert_eq!(block, encrypted_message); + } + + #[test] + fn test_aes_decryption(mut ctx: Context<'static>) { + let keytext = "SUp4SeCp@sSw0rd".as_bytes(); + let plaintext = "message".as_bytes(); + let mut encrypted_message = [ + 0xb3, 0xc8, 0xd2, 0x3b, 0xa7, 0x36, 0x5f, 0x18, 0x61, 0x70, 0x0, 0x3e, 0xd9, 0x3a, + 0x31, 0x96, + ]; + + // create an array with aes128 key size + let mut keybuf = [0_u8; 16]; + keybuf[..keytext.len()].copy_from_slice(keytext); + + ctx.aes + .process(&mut encrypted_message, Mode::Decryption128, &keybuf); + assert_eq!(&encrypted_message[..plaintext.len()], plaintext); + } +} diff --git a/hil-test/tests/gpio.rs b/hil-test/tests/gpio.rs new file mode 100644 index 00000000000..3e53a829af4 --- /dev/null +++ b/hil-test/tests/gpio.rs @@ -0,0 +1,72 @@ +//! GPIO Test +//! +//! Folowing pins are used: +//! GPIO2 +//! GPIO4 + +#![no_std] +#![no_main] + +use defmt_rtt as _; +use embedded_hal::digital::{InputPin as _, OutputPin as _, StatefulOutputPin as _}; +use esp_hal::{ + gpio::{GpioPin, Input, Output, PullDown, PushPull, IO}, + peripherals::Peripherals, +}; + +struct Context { + io2: GpioPin, 2>, + io4: GpioPin, 4>, +} + +impl Context { + pub fn init() -> Self { + let peripherals = Peripherals::take(); + let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + + Context { + io2: io.pins.gpio2.into_pull_down_input(), + io4: io.pins.gpio4.into_push_pull_output(), + } + } +} + +#[cfg(test)] +#[embedded_test::tests] +mod tests { + use defmt::assert_eq; + + use super::*; + + #[init] + fn init() -> Context { + Context::init() + } + + #[test] + fn test_gpio_input(mut ctx: Context) { + // `InputPin`: + assert_eq!(ctx.io2.is_low(), Ok(true)); + assert_eq!(ctx.io2.is_high(), Ok(false)); + } + + #[test] + fn test_gpio_output(mut ctx: Context) { + // `StatefulOutputPin`: + assert_eq!(ctx.io4.is_set_low(), Ok(true)); + assert_eq!(ctx.io4.is_set_high(), Ok(false)); + assert!(ctx.io4.set_high().is_ok()); + assert_eq!(ctx.io4.is_set_low(), Ok(false)); + assert_eq!(ctx.io4.is_set_high(), Ok(true)); + + // `ToggleableOutputPin`: + assert!(ctx.io4.toggle().is_ok()); + assert_eq!(ctx.io4.is_set_low(), Ok(true)); + assert_eq!(ctx.io4.is_set_high(), Ok(false)); + assert!(ctx.io4.toggle().is_ok()); + assert_eq!(ctx.io4.is_set_low(), Ok(false)); + assert_eq!(ctx.io4.is_set_high(), Ok(true)); + // Leave in initial state for next test + assert!(ctx.io4.toggle().is_ok()); + } +} diff --git a/hil-test/tests/spi_full_duplex.rs b/hil-test/tests/spi_full_duplex.rs new file mode 100644 index 00000000000..657183d971b --- /dev/null +++ b/hil-test/tests/spi_full_duplex.rs @@ -0,0 +1,115 @@ +//! SPI Full Duplex Test +//! +//! Folowing pins are used: +//! SCLK GPIO0 +//! MISO GPIO2 +//! MOSI GPIO4 +//! CS GPIO5 +//! +//! Connect MISO (GPIO2) and MOSI (GPIO4) pins. + +#![no_std] +#![no_main] + +use defmt_rtt as _; +use embedded_hal::spi::SpiBus; +use esp_hal::{ + clock::ClockControl, + gpio::IO, + peripherals::Peripherals, + prelude::*, + spi::{master::Spi, FullDuplexMode, SpiMode}, +}; + +struct Context { + spi: Spi<'static, esp_hal::peripherals::SPI2, FullDuplexMode>, +} + +impl Context { + pub fn init() -> Self { + let peripherals = Peripherals::take(); + let system = peripherals.SYSTEM.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + let sclk = io.pins.gpio0; + let miso = io.pins.gpio2; + let mosi = io.pins.gpio4; + let cs = io.pins.gpio5; + + let spi = Spi::new(peripherals.SPI2, 1000u32.kHz(), SpiMode::Mode0, &clocks).with_pins( + Some(sclk), + Some(mosi), + Some(miso), + Some(cs), + ); + + Context { spi } + } +} + +#[cfg(test)] +#[embedded_test::tests] +mod tests { + use defmt::assert_eq; + + use super::*; + + #[init] + fn init() -> Context { + Context::init() + } + + #[test] + fn test_symestric_transfer(mut ctx: Context) { + let write = [0xde, 0xad, 0xbe, 0xef]; + let mut read: [u8; 4] = [0x00u8; 4]; + + ctx.spi + .transfer(&mut read[..], &write[..]) + .expect("Symmetric transfer failed"); + assert_eq!(write, read); + } + + #[test] + fn test_asymestric_transfer(mut ctx: Context) { + let write = [0xde, 0xad, 0xbe, 0xef]; + let mut read: [u8; 4] = [0x00; 4]; + + ctx.spi + .transfer(&mut read[0..2], &write[..]) + .expect("Asymmetric transfer failed"); + assert_eq!(write[0], read[0]); + assert_eq!(read[2], 0x00u8); + } + + #[test] + fn test_symestric_transfer_huge_buffer(mut ctx: Context) { + let mut write = [0x55u8; 4096]; + for byte in 0..write.len() { + write[byte] = byte as u8; + } + let mut read = [0x00u8; 4096]; + + ctx.spi + .transfer(&mut read[..], &write[..]) + .expect("Huge transfer failed"); + assert_eq!(write, read); + } + + #[test] + #[timeout(3)] + fn test_symestric_transfer_huge_buffer_no_alloc(mut ctx: Context) { + let mut write = [0x55u8; 4096]; + for byte in 0..write.len() { + write[byte] = byte as u8; + } + + ctx.spi + .transfer_in_place(&mut write[..]) + .expect("Huge transfer failed"); + for byte in 0..write.len() { + assert_eq!(write[byte], byte as u8); + } + } +} diff --git a/hil-test/tests/uart.rs b/hil-test/tests/uart.rs new file mode 100644 index 00000000000..a06c11948ab --- /dev/null +++ b/hil-test/tests/uart.rs @@ -0,0 +1,73 @@ +//! UART Test +//! +//! Folowing pins are used: +//! TX GPIP2 +//! RX GPIO4 +//! +//! Connect TX (GPIO2) and RX (GPIO4) pins. + +#![no_std] +#![no_main] + +use defmt_rtt as _; +use embedded_hal_02::serial::{Read, Write}; +use esp_hal::{ + clock::ClockControl, + gpio::IO, + peripherals::{Peripherals, UART0}, + prelude::*, + uart::{ + config::{Config, DataBits, Parity, StopBits}, + TxRxPins, + Uart, + }, +}; +use nb::block; + +struct Context { + uart: Uart<'static, UART0>, +} + +impl Context { + pub fn init() -> Self { + let peripherals = Peripherals::take(); + let system = peripherals.SYSTEM.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + let pins = TxRxPins::new_tx_rx( + io.pins.gpio2.into_push_pull_output(), + io.pins.gpio4.into_floating_input(), + ); + let config = Config { + baudrate: 115200, + data_bits: DataBits::DataBits8, + parity: Parity::ParityNone, + stop_bits: StopBits::STOP1, + }; + + let uart = Uart::new_with_config(peripherals.UART0, config, Some(pins), &clocks); + + Context { uart } + } +} + +#[cfg(test)] +#[embedded_test::tests] +mod tests { + use defmt::assert_eq; + + use super::*; + + #[init] + fn init() -> Context { + Context::init() + } + + #[test] + #[timeout(3)] + fn test_send_receive(mut ctx: Context) { + ctx.uart.write(0x42).ok(); + let read = block!(ctx.uart.read()); + assert_eq!(read, Ok(0x42)); + } +} From 4e5020f83fd56e0365a77838d7495b4b420590ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Thu, 21 Mar 2024 16:16:44 +0100 Subject: [PATCH 04/16] Enable TWAI for ESP32-C6 (#1323) * Enable TWAI for ESP32-C6 * CHANGELOG.md * Make Clippy happy, again * Make Clippy happy. For real this time * Remove debug code --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/system.rs | 8 ++++++++ esp-hal/src/twai/mod.rs | 19 ++++++++++++++++--- examples/src/bin/embassy_twai.rs | 2 +- examples/src/bin/twai.rs | 2 +- 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index c7decb1b6aa..1ba21656b51 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `interrupt::enable` now has a direct CPU enable counter part, `interrupt::enable_direct` (#1310) - `Delay::delay(time: fugit::MicrosDurationU64)` - Added async support for TWAI (#1320) +- Add TWAI support for ESP32-C6 (#1323) ### Fixed diff --git a/esp-hal/src/system.rs b/esp-hal/src/system.rs index 8f5f9f41e2d..42f04036d50 100755 --- a/esp-hal/src/system.rs +++ b/esp-hal/src/system.rs @@ -684,6 +684,14 @@ impl PeripheralClockControl { system .twai0_conf() .modify(|_, w| w.twai0_rst_en().clear_bit()); + + // use Xtal clk-src + system.twai0_func_clk_conf().modify(|_, w| { + w.twai0_func_clk_en() + .set_bit() + .twai0_func_clk_sel() + .variant(false) + }); } #[cfg(twai1)] Peripheral::Twai1 => { diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index ae302af21b6..46ccb1ba506 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -81,6 +81,7 @@ use core::marker::PhantomData; use embedded_can::{nb::Can, Error, ErrorKind, ExtendedId, Frame, Id, StandardId}; #[cfg(not(feature = "embedded-hal"))] // FIXME use embedded_hal_02::can::{Can, Error, ErrorKind, ExtendedId, Frame, Id, StandardId}; +#[cfg(not(esp32c6))] use fugit::HertzU32; use self::filter::{Filter, FilterType}; @@ -227,8 +228,11 @@ impl BaudRate { // {.brp = 4, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false} // #define TWAI_TIMING_CONFIG_1MBITS() {.brp = 4, .tseg_1 = 15, .tseg_2 = 4, // .sjw = 3, .triple_sampling = false} + // + // see https://github.com/espressif/esp-idf/tree/master/components/hal/include/hal/twai_types.h const fn timing(self) -> TimingConfig { - match self { + #[allow(unused_mut)] + let mut timing = match self { Self::B125K => TimingConfig { baud_rate_prescaler: 32, sync_jump_width: 3, @@ -258,7 +262,15 @@ impl BaudRate { triple_sample: false, }, Self::Custom(timing_config) => timing_config, + }; + + #[cfg(esp32c6)] + { + // clock source on ESP32-C6 is xtal (40MHz) + timing.baud_rate_prescaler /= 2; } + + timing } } @@ -298,10 +310,11 @@ where /// Set the bitrate of the bus. /// /// Note: The timings currently assume a APB_CLK of 80MHz. - fn set_baud_rate(&mut self, baud_rate: BaudRate, clocks: &Clocks) { + fn set_baud_rate(&mut self, baud_rate: BaudRate, _clocks: &Clocks) { // TWAI is clocked from the APB_CLK according to Table 6-4 [ESP32C3 Reference Manual](https://www.espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf) // Included timings are all for 80MHz so assert that we are running at 80MHz. - assert!(clocks.apb_clock == HertzU32::MHz(80)); + #[cfg(not(esp32c6))] + assert!(_clocks.apb_clock == HertzU32::MHz(80)); // Unpack the baud rate timings and convert them to the values needed for the // register. Many of the registers have a minimum value of 1 which is diff --git a/examples/src/bin/embassy_twai.rs b/examples/src/bin/embassy_twai.rs index 3da9a69a397..a700fa0648e 100644 --- a/examples/src/bin/embassy_twai.rs +++ b/examples/src/bin/embassy_twai.rs @@ -10,7 +10,7 @@ //! This example should work with another ESP board running the `twai` example //! with `IS_SENDER` set to `true`. -//% CHIPS: esp32c3 esp32s2 esp32s3 +//% CHIPS: esp32c3 esp32c6 esp32s2 esp32s3 //% FEATURES: async embassy embassy-executor-thread embassy-time-timg0 embassy-generic-timers #![no_std] diff --git a/examples/src/bin/twai.rs b/examples/src/bin/twai.rs index b9bf67dd2e1..f92d15193c7 100644 --- a/examples/src/bin/twai.rs +++ b/examples/src/bin/twai.rs @@ -11,7 +11,7 @@ //! //! `IS_FIRST_SENDER` below must be set to false on one of the ESP's -//% CHIPS: esp32c3 esp32s2 esp32s3 +//% CHIPS: esp32c3 esp32c6 esp32s2 esp32s3 //% FEATURES: embedded-hal #![no_std] From 0cb5e4e82d5b50a308cdeb041ad7164d9d76701c Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Thu, 21 Mar 2024 15:36:33 +0000 Subject: [PATCH 05/16] Add the `esp-build` package, update `esp-hal` and `esp-lp-hal` to use it in their build scripts (#1325) * Create the `esp-build` package * Update `esp-hal` and `esp-lp-hal` to use `esp-build` --- Cargo.toml | 1 + esp-build/Cargo.toml | 16 +++ esp-build/README.md | 30 ++++++ esp-build/src/lib.rs | 222 ++++++++++++++++++++++++++++++++++++++++++ esp-hal/Cargo.toml | 1 + esp-hal/build.rs | 119 ++++++---------------- esp-lp-hal/Cargo.toml | 3 + esp-lp-hal/build.rs | 37 +------ 8 files changed, 304 insertions(+), 125 deletions(-) create mode 100644 esp-build/Cargo.toml create mode 100644 esp-build/README.md create mode 100644 esp-build/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index b86194ea725..3cce6d82f26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ resolver = "2" members = ["xtask"] exclude = [ + "esp-build", "esp-hal", "esp-hal-procmacros", "esp-hal-smartled", diff --git a/esp-build/Cargo.toml b/esp-build/Cargo.toml new file mode 100644 index 00000000000..d2d50068901 --- /dev/null +++ b/esp-build/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "esp-build" +version = "0.1.0" +edition = "2021" +rust-version = "1.60.0" +description = "Build utilities for esp-hal" +repository = "https://github.com/esp-rs/esp-hal" +license = "MIT OR Apache-2.0" + +[lib] +proc-macro = true + +[dependencies] +quote = "1.0.35" +syn = { version = "2.0.52", features = ["fold", "full"] } +termcolor = "1.4.1" diff --git a/esp-build/README.md b/esp-build/README.md new file mode 100644 index 00000000000..94d9c4dbf7f --- /dev/null +++ b/esp-build/README.md @@ -0,0 +1,30 @@ +# esp-build + +[![Crates.io](https://img.shields.io/crates/v/esp-build?color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp-build) +[![docs.rs](https://img.shields.io/docsrs/esp-build?color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp-build) +![MSRV](https://img.shields.io/badge/MSRV-1.60-blue?style=flat-square) +![Crates.io](https://img.shields.io/crates/l/esp-build?style=flat-square) + +Build utilities for `esp-hal`. + +## [Documentation](https://docs.rs/crate/esp-build) + +## Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust 1.60 and up. It _might_ +compile with older versions but that may change in any new patch release. + +## License + +Licensed under either of: + +- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in +the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without +any additional terms or conditions. diff --git a/esp-build/src/lib.rs b/esp-build/src/lib.rs new file mode 100644 index 00000000000..9999ee38b64 --- /dev/null +++ b/esp-build/src/lib.rs @@ -0,0 +1,222 @@ +//! Build utilities for esp-hal. + +#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")] + +use std::{io::Write as _, process}; + +use proc_macro::TokenStream; +use syn::{parse_macro_input, punctuated::Punctuated, LitStr, Token}; +use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; + +/// Print a build error and terminate the process. +/// +/// It should be noted that the error will be printed BEFORE the main function +/// is called, and as such this should NOT be thought analogous to `println!` or +/// similar utilities. +/// +/// ## Example +/// +/// ```rust +/// esp_build::error! {" +/// ERROR: something really bad has happened! +/// "} +/// // Process exits with exit code 1 +/// ``` +#[proc_macro] +pub fn error(input: TokenStream) -> TokenStream { + do_alert(Color::Red, input); + process::exit(1); +} + +/// Print a build warning. +/// +/// It should be noted that the warning will be printed BEFORE the main function +/// is called, and as such this should NOT be thought analogous to `println!` or +/// similar utilities. +/// +/// ## Example +/// +/// ```rust +/// esp_build::warning! {" +/// WARNING: something unpleasant has happened! +/// "}; +/// ``` +#[proc_macro] +pub fn warning(input: TokenStream) -> TokenStream { + do_alert(Color::Yellow, input) +} + +/// Given some features, assert that **at most** one of the features is enabled. +/// +/// ## Example +/// ```rust +/// assert_unique_features!("foo", "bar", "baz"); +/// ``` +#[proc_macro] +pub fn assert_unique_features(input: TokenStream) -> TokenStream { + let features = parse_macro_input!(input with Punctuated::parse_terminated) + .into_iter() + .collect::>(); + + let pairs = unique_pairs(&features); + let unique_cfgs = pairs + .iter() + .map(|(a, b)| quote::quote! { all(feature = #a, feature = #b) }); + + let message = format!( + r#" +ERROR: expected exactly zero or one enabled feature from feature group: + {:?} +"#, + features.iter().map(|lit| lit.value()).collect::>(), + ); + + quote::quote! { + #[cfg(any(#(#unique_cfgs),*))] + ::esp_build::error! { #message } + } + .into() +} + +/// Given some features, assert that **at least** one of the features is +/// enabled. +/// +/// ## Example +/// ```rust +/// assert_used_features!("foo", "bar", "baz"); +/// ``` +#[proc_macro] +pub fn assert_used_features(input: TokenStream) -> TokenStream { + let features = parse_macro_input!(input with Punctuated::parse_terminated) + .into_iter() + .collect::>(); + + let message = format!( + r#" +ERROR: expected at least one enabled feature from feature group: + {:?} + "#, + features.iter().map(|lit| lit.value()).collect::>() + ); + + quote::quote! { + #[cfg(not(any(#(feature = #features),*)))] + ::esp_build::error! { #message } + } + .into() +} + +/// Given some features, assert that **exactly** one of the features is enabled. +/// +/// ## Example +/// ```rust +/// assert_unique_used_features!("foo", "bar", "baz"); +/// ``` +#[proc_macro] +pub fn assert_unique_used_features(input: TokenStream) -> TokenStream { + let features = parse_macro_input!(input with Punctuated::parse_terminated) + .into_iter() + .collect::>(); + + let pairs = unique_pairs(&features); + let unique_cfgs = pairs + .iter() + .map(|(a, b)| quote::quote! { all(feature = #a, feature = #b) }); + + let message = format!( + r#" +ERROR: expected exactly one enabled feature from feature group: + {:?} + "#, + features.iter().map(|lit| lit.value()).collect::>() + ); + + quote::quote! { + #[cfg(any(any(#(#unique_cfgs),*), not(any(#(feature = #features),*))))] + ::esp_build::error! { #message } + } + .into() +} + +// ---------------------------------------------------------------------------- +// Helper Functions + +// Adapted from: +// https://github.com/dtolnay/build-alert/blob/49d060e/src/lib.rs#L54-L93 +fn do_alert(color: Color, input: TokenStream) -> TokenStream { + let message = parse_macro_input!(input as LitStr).value(); + + let ref mut stderr = StandardStream::stderr(ColorChoice::Auto); + let color_spec = ColorSpec::new().set_fg(Some(color)).clone(); + + let mut has_nonspace = false; + + for mut line in message.lines() { + if !has_nonspace { + let (maybe_heading, rest) = split_heading(line); + + if let Some(heading) = maybe_heading { + stderr.set_color(color_spec.clone().set_bold(true)).ok(); + write!(stderr, "\n{}", heading).ok(); + has_nonspace = true; + } + + line = rest; + } + + if line.is_empty() { + writeln!(stderr).ok(); + } else { + stderr.set_color(&color_spec).ok(); + writeln!(stderr, "{}", line).ok(); + + has_nonspace = has_nonspace || line.contains(|ch: char| ch != ' '); + } + } + + stderr.reset().ok(); + writeln!(stderr).ok(); + + TokenStream::new() +} + +// Adapted from: +// https://github.com/dtolnay/build-alert/blob/49d060e/src/lib.rs#L95-L114 +fn split_heading(s: &str) -> (Option<&str>, &str) { + let mut end = 0; + while end < s.len() && s[end..].starts_with(|ch: char| ch.is_ascii_uppercase()) { + end += 1; + } + + if end >= 3 && (end == s.len() || s[end..].starts_with(':')) { + let (heading, rest) = s.split_at(end); + (Some(heading), rest) + } else { + (None, s) + } +} + +fn unique_pairs(features: &Vec) -> Vec<(&LitStr, &LitStr)> { + let mut pairs = Vec::new(); + + let mut i = 0; + let mut j = 0; + + while i < features.len() { + let a = &features[i]; + let b = &features[j]; + + if a.value() != b.value() { + pairs.push((a, b)); + } + + j += 1; + + if j >= features.len() { + i += 1; + j = i; + } + } + + pairs +} diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml index e6a594fab82..48e03e9791a 100644 --- a/esp-hal/Cargo.toml +++ b/esp-hal/Cargo.toml @@ -70,6 +70,7 @@ xtensa-lx-rt = { version = "0.16.0", optional = true } [build-dependencies] basic-toml = "0.1.8" cfg-if = "1.0.0" +esp-build = { version = "0.1.0", path = "../esp-build" } esp-metadata = { version = "0.1.0", path = "../esp-metadata" } serde = { version = "1.0.197", features = ["derive"] } diff --git a/esp-hal/build.rs b/esp-hal/build.rs index efc6e90ab4e..755a774884c 100644 --- a/esp-hal/build.rs +++ b/esp-hal/build.rs @@ -7,45 +7,9 @@ use std::{ str::FromStr, }; +use esp_build::assert_unique_used_features; use esp_metadata::{Chip, Config}; -// Macros taken from: -// https://github.com/TheDan64/inkwell/blob/36c3b10/src/lib.rs#L81-L110 - -// Given some features, assert that AT MOST one of the features is enabled. -macro_rules! assert_unique_features { - () => {}; - - ( $first:tt $(,$rest:tt)* ) => { - $( - #[cfg(all(feature = $first, feature = $rest))] - compile_error!(concat!("Features \"", $first, "\" and \"", $rest, "\" cannot be used together")); - )* - assert_unique_features!($($rest),*); - }; -} - -// Given some features, assert that AT LEAST one of the features is enabled. -macro_rules! assert_used_features { - ( $all:tt ) => { - #[cfg(not(feature = $all))] - compile_error!(concat!("The feature flag must be provided: ", $all)); - }; - - ( $($all:tt),+ ) => { - #[cfg(not(any($(feature = $all),*)))] - compile_error!(concat!("One of the feature flags must be provided: ", $($all, ", "),*)); - }; -} - -// Given some features, assert that EXACTLY one of the features is enabled. -macro_rules! assert_unique_used_features { - ( $($all:tt),* ) => { - assert_unique_features!($($all),*); - assert_used_features!($($all),*); - } -} - fn main() -> Result<(), Box> { // NOTE: update when adding new device support! // Ensure that exactly one chip has been specified: @@ -56,23 +20,21 @@ fn main() -> Result<(), Box> { // If the `embassy` feature is enabled, ensure that a time driver implementation // is available: #[cfg(feature = "embassy")] - { - cfg_if::cfg_if! { - if #[cfg(feature = "esp32")] { - assert_unique_used_features!("embassy-time-timg0"); - } else if #[cfg(feature = "esp32s2")] { - assert_unique_used_features!("embassy-time-systick-80mhz", "embassy-time-timg0"); - } else { - assert_unique_used_features!("embassy-time-systick-16mhz", "embassy-time-timg0"); - } + cfg_if::cfg_if! { + if #[cfg(feature = "esp32")] { + assert_unique_used_features!("embassy-time-timg0"); + } else if #[cfg(feature = "esp32s2")] { + assert_unique_used_features!("embassy-time-systick-80mhz", "embassy-time-timg0"); + } else { + assert_unique_used_features!("embassy-time-systick-16mhz", "embassy-time-timg0"); } } - #[cfg(feature = "flip-link")] - { - #[cfg(not(any(feature = "esp32c6", feature = "esp32h2")))] - panic!("flip-link is only available on ESP32-C6/ESP32-H2"); - } + #[cfg(all( + feature = "flip-link", + not(any(feature = "esp32c6", feature = "esp32h2")) + ))] + esp_build::error!("flip-link is only available on ESP32-C6/ESP32-H2"); // NOTE: update when adding new device support! // Determine the name of the configured device: @@ -96,12 +58,6 @@ fn main() -> Result<(), Box> { unreachable!() // We've confirmed exactly one known device was selected }; - if detect_atomic_extension("a") || detect_atomic_extension("s32c1i") { - panic!( - "Atomic emulation flags detected in `.cargo/config.toml`, this is no longer supported!" - ); - } - // Load the configuration file for the configured device: let chip = Chip::from_str(device_name)?; let config = Config::for_chip(&chip); @@ -126,8 +82,14 @@ fn main() -> Result<(), Box> { let out = PathBuf::from(env::var_os("OUT_DIR").unwrap()); println!("cargo:rustc-link-search={}", out.display()); + // RISC-V and Xtensa devices each require some special handling and processing + // of linker scripts: + if cfg!(feature = "esp32") || cfg!(feature = "esp32s2") || cfg!(feature = "esp32s3") { - fs::copy("ld/xtensa/hal-defaults.x", out.join("hal-defaults.x"))?; + // Xtensa devices: + + #[cfg(any(feature = "esp32", feature = "esp32s2"))] + File::create(out.join("memory_extras.x"))?.write_all(&generate_memory_extras())?; let (irtc, drtc) = if cfg!(feature = "esp32s3") { ("rtc_fast_seg", "rtc_fast_seg") @@ -148,25 +110,30 @@ fn main() -> Result<(), Box> { ); fs::write(out.join("alias.x"), alias)?; + fs::copy("ld/xtensa/hal-defaults.x", out.join("hal-defaults.x"))?; } else { + // RISC-V devices: + + preprocess_file(&config_symbols, "ld/riscv/asserts.x", out.join("asserts.x"))?; + preprocess_file(&config_symbols, "ld/riscv/debug.x", out.join("debug.x"))?; preprocess_file( &config_symbols, "ld/riscv/hal-defaults.x", out.join("hal-defaults.x"), )?; - preprocess_file(&config_symbols, "ld/riscv/asserts.x", out.join("asserts.x"))?; - preprocess_file(&config_symbols, "ld/riscv/debug.x", out.join("debug.x"))?; } + // With the architecture-specific linker scripts taken care of, we can copy all + // remaining linker scripts which are common to all devices: copy_dir_all(&config_symbols, "ld/sections", &out)?; copy_dir_all(&config_symbols, format!("ld/{device_name}"), &out)?; - #[cfg(any(feature = "esp32", feature = "esp32s2"))] - File::create(out.join("memory_extras.x"))?.write_all(&generate_memory_extras())?; - Ok(()) } +// ---------------------------------------------------------------------------- +// Helper Functions + fn copy_dir_all( config_symbols: &Vec, src: impl AsRef, @@ -234,32 +201,6 @@ fn preprocess_file( Ok(()) } -fn detect_atomic_extension(ext: &str) -> bool { - let rustflags = env::var_os("CARGO_ENCODED_RUSTFLAGS") - .unwrap() - .into_string() - .unwrap(); - - // Users can pass -Ctarget-feature to the compiler multiple times, so we have to - // handle that - let target_flags = rustflags - .split(0x1f as char) - .filter_map(|s| s.strip_prefix("target-feature=")); - for tf in target_flags { - let tf = tf - .split(',') - .map(|s| s.trim()) - .filter_map(|s| s.strip_prefix('+')); - for tf in tf { - if tf == ext { - return true; - } - } - } - - false -} - #[cfg(feature = "esp32")] fn generate_memory_extras() -> Vec { let reserve_dram = if cfg!(feature = "bluetooth") { diff --git a/esp-lp-hal/Cargo.toml b/esp-lp-hal/Cargo.toml index e0b840571d2..946d1620a4d 100644 --- a/esp-lp-hal/Cargo.toml +++ b/esp-lp-hal/Cargo.toml @@ -35,6 +35,9 @@ riscv = { version = "0.11.0", features = ["critical-section-single-har [dev-dependencies] panic-halt = "0.2.0" +[build-dependencies] +esp-build = { version = "0.1.0", path = "../esp-build" } + [features] default = ["embedded-hal-02"] diff --git a/esp-lp-hal/build.rs b/esp-lp-hal/build.rs index 93391ecd74a..855e816cdd0 100644 --- a/esp-lp-hal/build.rs +++ b/esp-lp-hal/build.rs @@ -1,41 +1,6 @@ use std::{env, error::Error, fs, path::PathBuf}; -// Macros taken from: -// https://github.com/TheDan64/inkwell/blob/36c3b10/src/lib.rs#L81-L110 - -// Given some features, assert that AT MOST one of the features is enabled. -macro_rules! assert_unique_features { - () => {}; - - ( $first:tt $(,$rest:tt)* ) => { - $( - #[cfg(all(feature = $first, feature = $rest))] - compile_error!(concat!("Features \"", $first, "\" and \"", $rest, "\" cannot be used together")); - )* - assert_unique_features!($($rest),*); - }; -} - -// Given some features, assert that AT LEAST one of the features is enabled. -macro_rules! assert_used_features { - ( $all:tt ) => { - #[cfg(not(feature = $all))] - compile_error!(concat!("The feature flag must be provided: ", $all)); - }; - - ( $($all:tt),+ ) => { - #[cfg(not(any($(feature = $all),*)))] - compile_error!(concat!("One of the feature flags must be provided: ", $($all, ", "),*)); - }; -} - -// Given some features, assert that EXACTLY one of the features is enabled. -macro_rules! assert_unique_used_features { - ( $($all:tt),* ) => { - assert_unique_features!($($all),*); - assert_used_features!($($all),*); - } -} +use esp_build::assert_unique_used_features; fn main() -> Result<(), Box> { // NOTE: update when adding new device support! From 25f509ce74d4c44f5bc6adfeb82d5525f93332c8 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 21 Mar 2024 15:38:07 +0000 Subject: [PATCH 06/16] discard interrupt symbols from lto so that lto doesn't end up rebinding them (#1327) --- esp-hal/ld/riscv/hal-defaults.x | 62 ++++++++-------- esp-hal/src/interrupt/riscv.rs | 38 +++++----- esp-riscv-rt/src/lib.rs | 127 ++++++++++++++++---------------- examples/Cargo.toml | 8 +- hil-test/Cargo.toml | 36 +++------ 5 files changed, 132 insertions(+), 139 deletions(-) diff --git a/esp-hal/ld/riscv/hal-defaults.x b/esp-hal/ld/riscv/hal-defaults.x index 1d845d3e6da..133577f3958 100644 --- a/esp-hal/ld/riscv/hal-defaults.x +++ b/esp-hal/ld/riscv/hal-defaults.x @@ -1,35 +1,35 @@ PROVIDE(DefaultHandler = EspDefaultHandler); -PROVIDE(cpu_int_1_handler = DefaultHandler); -PROVIDE(cpu_int_2_handler = DefaultHandler); -PROVIDE(cpu_int_3_handler = DefaultHandler); -PROVIDE(cpu_int_4_handler = DefaultHandler); -PROVIDE(cpu_int_5_handler = DefaultHandler); -PROVIDE(cpu_int_6_handler = DefaultHandler); -PROVIDE(cpu_int_7_handler = DefaultHandler); -PROVIDE(cpu_int_8_handler = DefaultHandler); -PROVIDE(cpu_int_9_handler = DefaultHandler); -PROVIDE(cpu_int_10_handler = DefaultHandler); -PROVIDE(cpu_int_11_handler = DefaultHandler); -PROVIDE(cpu_int_12_handler = DefaultHandler); -PROVIDE(cpu_int_13_handler = DefaultHandler); -PROVIDE(cpu_int_14_handler = DefaultHandler); -PROVIDE(cpu_int_15_handler = DefaultHandler); -PROVIDE(cpu_int_16_handler = DefaultHandler); -PROVIDE(cpu_int_17_handler = DefaultHandler); -PROVIDE(cpu_int_18_handler = DefaultHandler); -PROVIDE(cpu_int_19_handler = DefaultHandler); -PROVIDE(cpu_int_20_handler = DefaultHandler); -PROVIDE(cpu_int_21_handler = DefaultHandler); -PROVIDE(cpu_int_22_handler = DefaultHandler); -PROVIDE(cpu_int_23_handler = DefaultHandler); -PROVIDE(cpu_int_24_handler = DefaultHandler); -PROVIDE(cpu_int_25_handler = DefaultHandler); -PROVIDE(cpu_int_26_handler = DefaultHandler); -PROVIDE(cpu_int_27_handler = DefaultHandler); -PROVIDE(cpu_int_28_handler = DefaultHandler); -PROVIDE(cpu_int_29_handler = DefaultHandler); -PROVIDE(cpu_int_30_handler = DefaultHandler); -PROVIDE(cpu_int_31_handler = DefaultHandler); +PROVIDE(interrupt1 = DefaultHandler); +PROVIDE(interrupt2 = DefaultHandler); +PROVIDE(interrupt3 = DefaultHandler); +PROVIDE(interrupt4 = DefaultHandler); +PROVIDE(interrupt5 = DefaultHandler); +PROVIDE(interrupt6 = DefaultHandler); +PROVIDE(interrupt7 = DefaultHandler); +PROVIDE(interrupt8 = DefaultHandler); +PROVIDE(interrupt9 = DefaultHandler); +PROVIDE(interrupt10 = DefaultHandler); +PROVIDE(interrupt11 = DefaultHandler); +PROVIDE(interrupt12 = DefaultHandler); +PROVIDE(interrupt13 = DefaultHandler); +PROVIDE(interrupt14 = DefaultHandler); +PROVIDE(interrupt15 = DefaultHandler); +PROVIDE(interrupt16 = DefaultHandler); +PROVIDE(interrupt17 = DefaultHandler); +PROVIDE(interrupt18 = DefaultHandler); +PROVIDE(interrupt19 = DefaultHandler); +PROVIDE(interrupt20 = DefaultHandler); +PROVIDE(interrupt21 = DefaultHandler); +PROVIDE(interrupt22 = DefaultHandler); +PROVIDE(interrupt23 = DefaultHandler); +PROVIDE(interrupt24 = DefaultHandler); +PROVIDE(interrupt25 = DefaultHandler); +PROVIDE(interrupt26 = DefaultHandler); +PROVIDE(interrupt27 = DefaultHandler); +PROVIDE(interrupt28 = DefaultHandler); +PROVIDE(interrupt29 = DefaultHandler); +PROVIDE(interrupt30 = DefaultHandler); +PROVIDE(interrupt31 = DefaultHandler); INCLUDE "device.x" diff --git a/esp-hal/src/interrupt/riscv.rs b/esp-hal/src/interrupt/riscv.rs index f941628fa79..58bcde4e4d4 100644 --- a/esp-hal/src/interrupt/riscv.rs +++ b/esp-hal/src/interrupt/riscv.rs @@ -439,119 +439,119 @@ mod vectored { #[no_mangle] #[ram] - unsafe fn cpu_int_1_handler(context: &mut TrapFrame) { + unsafe fn interrupt1(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt1, context) } #[no_mangle] #[ram] - unsafe fn cpu_int_2_handler(context: &mut TrapFrame) { + unsafe fn interrupt2(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt2, context) } #[no_mangle] #[ram] - unsafe fn cpu_int_3_handler(context: &mut TrapFrame) { + unsafe fn interrupt3(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt3, context) } #[no_mangle] #[ram] - unsafe fn cpu_int_4_handler(context: &mut TrapFrame) { + unsafe fn interrupt4(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt4, context) } #[no_mangle] #[ram] - unsafe fn cpu_int_5_handler(context: &mut TrapFrame) { + unsafe fn interrupt5(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt5, context) } #[no_mangle] #[ram] - unsafe fn cpu_int_6_handler(context: &mut TrapFrame) { + unsafe fn interrupt6(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt6, context) } #[no_mangle] #[ram] - unsafe fn cpu_int_7_handler(context: &mut TrapFrame) { + unsafe fn interrupt7(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt7, context) } #[no_mangle] #[ram] - unsafe fn cpu_int_8_handler(context: &mut TrapFrame) { + unsafe fn interrupt8(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt8, context) } #[no_mangle] #[ram] - unsafe fn cpu_int_9_handler(context: &mut TrapFrame) { + unsafe fn interrupt9(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt9, context) } #[no_mangle] #[ram] - unsafe fn cpu_int_10_handler(context: &mut TrapFrame) { + unsafe fn interrupt10(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt10, context) } #[no_mangle] #[ram] - unsafe fn cpu_int_11_handler(context: &mut TrapFrame) { + unsafe fn interrupt11(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt11, context) } #[no_mangle] #[ram] - unsafe fn cpu_int_12_handler(context: &mut TrapFrame) { + unsafe fn interrupt12(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt12, context) } #[no_mangle] #[ram] - unsafe fn cpu_int_13_handler(context: &mut TrapFrame) { + unsafe fn interrupt13(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt13, context) } #[no_mangle] #[ram] - unsafe fn cpu_int_14_handler(context: &mut TrapFrame) { + unsafe fn interrupt14(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt14, context) } #[no_mangle] #[ram] - unsafe fn cpu_int_15_handler(context: &mut TrapFrame) { + unsafe fn interrupt15(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt15, context) } #[cfg(plic)] #[no_mangle] #[ram] - unsafe fn cpu_int_16_handler(context: &mut TrapFrame) { + unsafe fn interrupt16(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt16, context) } #[cfg(plic)] #[no_mangle] #[ram] - unsafe fn cpu_int_17_handler(context: &mut TrapFrame) { + unsafe fn interrupt17(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt17, context) } #[cfg(plic)] #[no_mangle] #[ram] - unsafe fn cpu_int_18_handler(context: &mut TrapFrame) { + unsafe fn interrupt18(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt18, context) } #[cfg(plic)] #[no_mangle] #[ram] - unsafe fn cpu_int_19_handler(context: &mut TrapFrame) { + unsafe fn interrupt19(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt19, context) } } diff --git a/esp-riscv-rt/src/lib.rs b/esp-riscv-rt/src/lib.rs index d9d14019711..3ff1f837a06 100644 --- a/esp-riscv-rt/src/lib.rs +++ b/esp-riscv-rt/src/lib.rs @@ -512,157 +512,157 @@ r#" _start_trap1: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_1_handler + la ra, interrupt1 j _start_trap_direct _start_trap2: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_2_handler + la ra, interrupt2 j _start_trap_direct _start_trap3: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_3_handler + la ra, interrupt3 j _start_trap_direct _start_trap4: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_4_handler + la ra, interrupt4 j _start_trap_direct _start_trap5: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_5_handler + la ra, interrupt5 j _start_trap_direct _start_trap6: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_6_handler + la ra, interrupt6 j _start_trap_direct _start_trap7: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_7_handler + la ra, interrupt7 j _start_trap_direct _start_trap8: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_8_handler + la ra, interrupt8 j _start_trap_direct _start_trap9: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_9_handler + la ra, interrupt9 j _start_trap_direct _start_trap10: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_10_handler + la ra, interrupt10 j _start_trap_direct _start_trap11: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_11_handler + la ra, interrupt11 j _start_trap_direct _start_trap12: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_12_handler + la ra, interrupt12 j _start_trap_direct _start_trap13: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_13_handler + la ra, interrupt13 j _start_trap_direct _start_trap14: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_14_handler + la ra, interrupt14 j _start_trap_direct _start_trap15: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_15_handler + la ra, interrupt15 j _start_trap_direct _start_trap16: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_16_handler + la ra, interrupt16 j _start_trap_direct _start_trap17: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_17_handler + la ra, interrupt17 j _start_trap_direct _start_trap18: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_18_handler + la ra, interrupt18 j _start_trap_direct _start_trap19: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_19_handler + la ra, interrupt19 j _start_trap_direct _start_trap20: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_20_handler + la ra, interrupt20 j _start_trap_direct _start_trap21: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_21_handler + la ra, interrupt21 j _start_trap_direct _start_trap22: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_22_handler + la ra, interrupt22 j _start_trap_direct _start_trap23: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_23_handler + la ra, interrupt23 j _start_trap_direct _start_trap24: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_24_handler + la ra, interrupt24 j _start_trap_direct _start_trap25: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_25_handler + la ra, interrupt25 j _start_trap_direct _start_trap26: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_26_handler + la ra, interrupt26 j _start_trap_direct _start_trap27: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_27_handler + la ra, interrupt27 j _start_trap_direct _start_trap28: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_28_handler + la ra, interrupt28 j _start_trap_direct _start_trap29: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_29_handler + la ra, interrupt29 j _start_trap_direct _start_trap30: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_30_handler + la ra, interrupt30 j _start_trap_direct _start_trap31: addi sp, sp, -40*4 sw ra, 0(sp) - la ra, cpu_int_31_handler + la ra, interrupt31 j _start_trap_direct la ra, _start_trap_rust_hal /* this runs on exception, use regular fault handler */ _start_trap_direct: @@ -829,36 +829,39 @@ _vector_table: r#" #this is required for the linking step, these symbols for in-use interrupts should always be overwritten by the user. .section .trap, "ax" -.weak cpu_int_1_handler -.weak cpu_int_2_handler -.weak cpu_int_3_handler -.weak cpu_int_4_handler -.weak cpu_int_5_handler -.weak cpu_int_6_handler -.weak cpu_int_7_handler -.weak cpu_int_8_handler -.weak cpu_int_9_handler -.weak cpu_int_10_handler -.weak cpu_int_11_handler -.weak cpu_int_12_handler -.weak cpu_int_13_handler -.weak cpu_int_14_handler -.weak cpu_int_15_handler -.weak cpu_int_16_handler -.weak cpu_int_17_handler -.weak cpu_int_18_handler -.weak cpu_int_19_handler -.weak cpu_int_20_handler -.weak cpu_int_21_handler -.weak cpu_int_22_handler -.weak cpu_int_23_handler -.weak cpu_int_24_handler -.weak cpu_int_25_handler -.weak cpu_int_26_handler -.weak cpu_int_27_handler -.weak cpu_int_28_handler -.weak cpu_int_29_handler -.weak cpu_int_30_handler -.weak cpu_int_31_handler +// See https://github.com/esp-rs/esp-hal/issues/1326 and https://reviews.llvm.org/D98762 +// and yes, this all has to go on one line... *sigh*. +.lto_discard interrupt1, interrupt2, interrupt3, interrupt4, interrupt5, interrupt6, interrupt7, interrupt8, interrupt9, interrupt10, interrupt11, interrupt12, interrupt13, interrupt14, interrupt15, interrupt16, interrupt17, interrupt18, interrupt19, interrupt20, interrupt21, interrupt22, interrupt23, interrupt24, interrupt25, interrupt26, interrupt27, interrupt28, interrupt29, interrupt30, interrupt31 +.weak interrupt1 +.weak interrupt2 +.weak interrupt3 +.weak interrupt4 +.weak interrupt5 +.weak interrupt6 +.weak interrupt7 +.weak interrupt8 +.weak interrupt9 +.weak interrupt10 +.weak interrupt11 +.weak interrupt12 +.weak interrupt13 +.weak interrupt14 +.weak interrupt15 +.weak interrupt16 +.weak interrupt17 +.weak interrupt18 +.weak interrupt19 +.weak interrupt20 +.weak interrupt21 +.weak interrupt22 +.weak interrupt23 +.weak interrupt24 +.weak interrupt25 +.weak interrupt26 +.weak interrupt27 +.weak interrupt28 +.weak interrupt29 +.weak interrupt30 +.weak interrupt31 "#, } diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 7bc78bb4242..c83f4275bc2 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -70,7 +70,13 @@ opsram-2m = ["esp-hal/opsram-2m"] psram-2m = ["esp-hal/psram-2m"] [profile.release] -debug = true +codegen-units = 1 +debug = 2 +debug-assertions = false +incremental = false +opt-level = 3 +lto = 'fat' +overflow-checks = false [patch.crates-io] esp32 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml index dd1f5a5dde2..39e6c18aa62 100644 --- a/hil-test/Cargo.toml +++ b/hil-test/Cargo.toml @@ -53,41 +53,25 @@ embassy-time-systick-16mhz = ["esp-hal?/embassy-time-systick-16mhz"] embassy-time-systick-80mhz = ["esp-hal?/embassy-time-systick-80mhz"] embassy-time-timg0 = ["esp-hal?/embassy-time-timg0"] -# cargo build/run -[profile.dev] -codegen-units = 1 -debug = 2 -debug-assertions = true # <- -incremental = false -opt-level = 'z' # <- -overflow-checks = true # <- +# https://doc.rust-lang.org/cargo/reference/profiles.html#test +# Test and bench profiles inherit from dev and release respectively. -# cargo test -[profile.test] +[profile.dev] codegen-units = 1 debug = 2 -debug-assertions = true # <- +debug-assertions = true incremental = false -opt-level = 3 # <- -overflow-checks = true # <- +opt-level = 'z' +overflow-checks = true -# cargo build/run --release [profile.release] codegen-units = 1 debug = 2 -debug-assertions = false # <- -incremental = false -opt-level = 3 # <- -overflow-checks = false # <- - -# cargo test --release -[profile.bench] -codegen-units = 1 -debug = 2 -debug-assertions = false # <- +debug-assertions = false incremental = false -opt-level = 3 # <- -overflow-checks = false # <- +opt-level = 3 +lto = 'fat' +overflow-checks = false [patch.crates-io] semihosting = { git = "https://github.com/taiki-e/semihosting", rev = "c829c19" } From 93d31e76d803aa699e8fac493362741579e9a92e Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 21 Mar 2024 15:45:35 +0000 Subject: [PATCH 07/16] Add InterruptHandler wrapper (#1299) * Add InterruptHandler * Which takes the handler and a prio. * Updates the `#[handler]` macro to create this for us. * changelog --- esp-hal-procmacros/src/lib.rs | 22 +++++++++++++++++++- esp-hal/CHANGELOG.md | 1 + esp-hal/src/gpio.rs | 32 ++++++++++++++++++++---------- esp-hal/src/interrupt/mod.rs | 28 ++++++++++++++++++++++++++ esp-hal/src/interrupt/riscv.rs | 5 +++-- esp-hal/src/interrupt/xtensa.rs | 4 ++-- examples/src/bin/gpio_interrupt.rs | 12 +++++------ 7 files changed, 81 insertions(+), 23 deletions(-) diff --git a/esp-hal-procmacros/src/lib.rs b/esp-hal-procmacros/src/lib.rs index de69cab27ce..1f285faa870 100644 --- a/esp-hal-procmacros/src/lib.rs +++ b/esp-hal-procmacros/src/lib.rs @@ -368,6 +368,8 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { use darling::ast::NestedMeta; use proc_macro::Span; + use proc_macro2::Ident; + use proc_macro_crate::{crate_name, FoundCrate}; use proc_macro_error::abort; use syn::{parse::Error as ParseError, spanned::Spanned, ItemFn, ReturnType, Type}; @@ -417,10 +419,28 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { .into(); } + let root = Ident::new( + if let Ok(FoundCrate::Name(ref name)) = crate_name("esp-hal") { + &name + } else { + "crate" + }, + Span::call_site().into(), + ); + f.sig.abi = syn::parse_quote_spanned!(original_span => extern "C"); + let orig = f.sig.ident; + f.sig.ident = Ident::new( + &format!("__esp_hal_internal_{}", orig), + proc_macro2::Span::call_site(), + ); + let new = f.sig.ident.clone(); - quote::quote_spanned!( original_span => + quote::quote_spanned!(original_span => #f + + #[allow(non_upper_case_globals)] + static #orig: #root::interrupt::InterruptHandler = #root::interrupt::InterruptHandler::new(#new, #root::interrupt::Priority::min()); ) .into() } diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 1ba21656b51..a5f9eec936c 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -65,6 +65,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensuring that the random number generator is TRNG. (#1200) - ESP32-C6: Add timer wakeup source for deepsleep (#1201) - Introduce `InterruptExecutor::spawner()` (#1211) +- Add `InterruptHandler` struct, which couples interrupt handlers and their priority together (#1299) ### Fixed diff --git a/esp-hal/src/gpio.rs b/esp-hal/src/gpio.rs index c0b3b425b85..55f68b717ab 100644 --- a/esp-hal/src/gpio.rs +++ b/esp-hal/src/gpio.rs @@ -30,10 +30,13 @@ use procmacros::handler; #[cfg(any(adc, dac))] pub(crate) use crate::analog; pub(crate) use crate::gpio; -use crate::peripherals::{GPIO, IO_MUX}; #[cfg(any(xtensa, esp32c3))] pub(crate) use crate::rtc_pins; pub use crate::soc::gpio::*; +use crate::{ + interrupt::InterruptHandler, + peripherals::{GPIO, IO_MUX}, +}; /// Convenience type-alias for a no-pin / don't care - pin pub type NoPinType = Gpio0; @@ -41,8 +44,7 @@ pub type NoPinType = Gpio0; /// Convenience constant for `Option::None` pin pub const NO_PIN: Option = None; -static USER_INTERRUPT_HANDLER: Mutex>> = - Mutex::new(Cell::new(None)); +static USER_INTERRUPT_HANDLER: Mutex>> = Mutex::new(Cell::new(None)); #[derive(Copy, Clone)] pub enum Event { @@ -1872,9 +1874,9 @@ pub struct IO { } impl IO { + /// Initialize the I/O driver. pub fn new(mut gpio: GPIO, io_mux: IO_MUX) -> Self { - gpio.bind_gpio_interrupt(gpio_interrupt_handler); - + gpio.bind_gpio_interrupt(gpio_interrupt_handler.handler()); let pins = gpio.split(); IO { @@ -1883,6 +1885,15 @@ impl IO { } } + /// Initialize the I/O driver with a interrupt priority. + /// + /// This decides the priority for the interrupt when only using async. + pub fn new_with_priority(gpio: GPIO, io_mux: IO_MUX, prio: crate::interrupt::Priority) -> Self { + crate::interrupt::enable(crate::peripherals::Interrupt::GPIO, prio).unwrap(); + + Self::new(gpio, io_mux) + } + /// Install the given interrupt handler replacing any previously set /// handler. /// @@ -1890,20 +1901,20 @@ impl IO { /// the internal async handler will run after. In that case it's /// important to not reset the interrupt status when mixing sync and /// async (i.e. using async wait) interrupt handling. - pub fn set_interrupt_handler(&mut self, handler: unsafe extern "C" fn() -> ()) { + pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { critical_section::with(|cs| { + crate::interrupt::enable(crate::peripherals::Interrupt::GPIO, handler.priority()) + .unwrap(); USER_INTERRUPT_HANDLER.borrow(cs).set(Some(handler)); }); } } #[handler] -unsafe fn gpio_interrupt_handler() { +fn gpio_interrupt_handler() { if let Some(user_handler) = critical_section::with(|cs| USER_INTERRUPT_HANDLER.borrow(cs).get()) { - unsafe { - user_handler(); - } + user_handler.call(); } #[cfg(feature = "async")] @@ -3095,7 +3106,6 @@ mod asynch { use embedded_hal_async::digital::Wait; use super::*; - use crate::prelude::*; #[allow(clippy::declare_interior_mutable_const)] const NEW_AW: AtomicWaker = AtomicWaker::new(); diff --git a/esp-hal/src/interrupt/mod.rs b/esp-hal/src/interrupt/mod.rs index 5652e0b8b5e..59c237321d6 100644 --- a/esp-hal/src/interrupt/mod.rs +++ b/esp-hal/src/interrupt/mod.rs @@ -60,3 +60,31 @@ pub use self::xtensa::*; mod riscv; #[cfg(xtensa)] mod xtensa; + +/// An interrupt handler +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct InterruptHandler { + f: extern "C" fn(), + prio: Priority, +} + +impl InterruptHandler { + pub const fn new(f: extern "C" fn(), prio: Priority) -> Self { + Self { f, prio } + } + + #[inline] + pub fn handler(&self) -> extern "C" fn() { + self.f + } + + #[inline] + pub fn priority(&self) -> Priority { + self.prio + } + + #[inline] + pub(crate) extern "C" fn call(&self) { + (self.f)() + } +} diff --git a/esp-hal/src/interrupt/riscv.rs b/esp-hal/src/interrupt/riscv.rs index 58bcde4e4d4..26a90a4aad0 100644 --- a/esp-hal/src/interrupt/riscv.rs +++ b/esp-hal/src/interrupt/riscv.rs @@ -88,6 +88,7 @@ pub enum CpuInterrupt { } /// Interrupt priority levels. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] pub enum Priority { @@ -118,7 +119,7 @@ pub enum Priority { } impl Priority { - pub fn max() -> Priority { + pub const fn max() -> Priority { cfg_if::cfg_if! { if #[cfg(not(clic))] { Priority::Priority15 @@ -128,7 +129,7 @@ impl Priority { } } - pub fn min() -> Priority { + pub const fn min() -> Priority { Priority::Priority1 } } diff --git a/esp-hal/src/interrupt/xtensa.rs b/esp-hal/src/interrupt/xtensa.rs index 6b1b4d7a6a0..7545a951a8c 100644 --- a/esp-hal/src/interrupt/xtensa.rs +++ b/esp-hal/src/interrupt/xtensa.rs @@ -241,11 +241,11 @@ mod vectored { } impl Priority { - pub fn max() -> Priority { + pub const fn max() -> Priority { Priority::Priority3 } - pub fn min() -> Priority { + pub const fn min() -> Priority { Priority::Priority1 } } diff --git a/examples/src/bin/gpio_interrupt.rs b/examples/src/bin/gpio_interrupt.rs index 1b6015e8c8f..a447812b350 100644 --- a/examples/src/bin/gpio_interrupt.rs +++ b/examples/src/bin/gpio_interrupt.rs @@ -18,9 +18,8 @@ use esp_hal::{ clock::ClockControl, delay::Delay, gpio::{self, Event, Input, PullDown, IO}, - interrupt::{self, Priority}, macros::ram, - peripherals::{Interrupt, Peripherals}, + peripherals::Peripherals, prelude::*, }; @@ -46,12 +45,11 @@ fn main() -> ! { let mut button = io.pins.gpio0.into_pull_down_input(); #[cfg(not(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3")))] let mut button = io.pins.gpio9.into_pull_down_input(); - button.listen(Event::FallingEdge); - - critical_section::with(|cs| BUTTON.borrow_ref_mut(cs).replace(button)); - - interrupt::enable(Interrupt::GPIO, Priority::Priority2).unwrap(); + critical_section::with(|cs| { + button.listen(Event::FallingEdge); + BUTTON.borrow_ref_mut(cs).replace(button) + }); led.set_high().unwrap(); // Initialize the Delay peripheral, and use it to toggle the LED state in a From bc74a446a4d3cfe24edd9410f7b1b2ea674f72b4 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Thu, 21 Mar 2024 16:57:51 +0000 Subject: [PATCH 08/16] Add dummy CI jobs to (hopefully) make our HIL testing work with merge queues (#1331) --- .github/workflows/ci.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f5dc050c325..0adbdc59f9a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -298,3 +298,23 @@ jobs: run: cargo fmt --all --manifest-path=esp-riscv-rt/Cargo.toml -- --check - name: rustfmt (examples) run: cargo fmt --all --manifest-path=examples/Cargo.toml -- --check + + # -------------------------------------------------------------------------- + # NOTE: + # + # This is (hopefully) a temporary workaround to allow us to run HIL tests + # in merge queue, but not in pull requests. For more information see: + # + # https://github.com/esp-rs/esp-hal/issues/1328 + + riscv-hil: + name: HIL Test | ${{ matrix.soc }} + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + soc: [esp32c3, esp32c6, esp32h2] + + steps: + - run: echo "HIL tests are not run in pull requests!" From d5e499577703d48cd7abe50330c07c1c4f1b8022 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 21 Mar 2024 21:51:09 +0000 Subject: [PATCH 09/16] uart: allow driver to init as blocking or async (#1294) * uart: allow driver to init as blocking or async * adds a mode type param to Uart types * remove #[interrupt] usage * add constructor for blocking and async modes * blocking constructor takes optional interrupt * async chooses the correct handler to bind at runtime * moves interrupt enable for uart into the driver * changelog --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/embassy/mod.rs | 5 - esp-hal/src/fmt.rs | 1 + esp-hal/src/lib.rs | 14 ++ esp-hal/src/uart.rs | 238 ++++++++++++++++++-------- examples/src/bin/advanced_serial.rs | 2 +- examples/src/bin/embassy_serial.rs | 13 +- examples/src/bin/lp_core_uart.rs | 2 +- examples/src/bin/serial_interrupts.rs | 3 +- hil-test/tests/uart.rs | 5 +- 10 files changed, 200 insertions(+), 84 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index a5f9eec936c..bf1ffa2a413 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support runtime interrupt binding, adapt GPIO driver (#1231) - Renamed `eh1` feature to `embedded-hal`, feature-gated `embedded-hal@0.2.x` trait implementations (#1273) - Enable `embedded-hal` feature by default, instead of the `embedded-hal-02` feature (#1313) +- `Uart` structs now take a `Mode` parameter which defines how the driver is initialized (#1294) ### Removed diff --git a/esp-hal/src/embassy/mod.rs b/esp-hal/src/embassy/mod.rs index 453cbfb1fba..cba292ba767 100644 --- a/esp-hal/src/embassy/mod.rs +++ b/esp-hal/src/embassy/mod.rs @@ -163,11 +163,6 @@ pub fn init(clocks: &Clocks, td: time_driver::TimerType) { #[cfg(all(parl_io, esp32h2))] crate::interrupt::enable(Interrupt::PARL_IO_TX, Priority::min()).unwrap(); - #[cfg(uart0)] - crate::interrupt::enable(Interrupt::UART0, Priority::min()).unwrap(); - #[cfg(uart1)] - crate::interrupt::enable(Interrupt::UART1, Priority::min()).unwrap(); - crate::interrupt::enable(Interrupt::I2C_EXT0, Priority::min()).unwrap(); crate::interrupt::enable(Interrupt::GPIO, Priority::min()).unwrap(); diff --git a/esp-hal/src/fmt.rs b/esp-hal/src/fmt.rs index 06697081337..aa009027405 100644 --- a/esp-hal/src/fmt.rs +++ b/esp-hal/src/fmt.rs @@ -201,6 +201,7 @@ pub struct NoneError; pub trait Try { type Ok; type Error; + #[allow(unused)] fn into_result(self) -> Result; } diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index ee3dd564cb3..fd4b4f5b838 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -154,6 +154,20 @@ extern "C" fn EspDefaultHandler(_interrupt: peripherals::Interrupt) { ); } +/// A marker trait for intializing drivers in a specific mode. +pub trait Mode: crate::private::Sealed {} + +/// Driver initialized in blocking mode. +pub struct Blocking; + +/// Driver initialized in async mode. +pub struct Async; + +impl crate::Mode for Blocking {} +impl crate::Mode for Async {} +impl crate::private::Sealed for Blocking {} +impl crate::private::Sealed for Async {} + pub(crate) mod private { pub trait Sealed {} } diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index 5e407e3784b..2582bc09f6c 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -47,10 +47,16 @@ use core::marker::PhantomData; use self::config::Config; use crate::{ clock::Clocks, - gpio::{InputPin, InputSignal, OutputPin, OutputSignal}, + gpio::{InputPin, InputSignal, NoPinType, OutputPin, OutputSignal}, + interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, - peripherals::uart0::{fifo::FIFO_SPEC, RegisterBlock}, + peripherals::{ + uart0::{fifo::FIFO_SPEC, RegisterBlock}, + Interrupt, + }, system::PeripheralClockControl, + Blocking, + Mode, }; const CONSOLE_UART_NUM: usize = 0; @@ -317,35 +323,30 @@ impl UartPins for TxRxPins<'_, TX, RX> { } /// UART driver -pub struct Uart<'d, T> { +pub struct Uart<'d, T, M> { #[cfg(not(esp32))] symbol_len: u8, - tx: UartTx<'d, T>, - rx: UartRx<'d, T>, + tx: UartTx<'d, T, M>, + rx: UartRx<'d, T, M>, } /// UART TX -pub struct UartTx<'d, T> { - phantom: PhantomData<&'d mut T>, +pub struct UartTx<'d, T, M> { + phantom: PhantomData<(&'d mut T, M)>, } /// UART RX -pub struct UartRx<'d, T> { - phantom: PhantomData<&'d mut T>, +pub struct UartRx<'d, T, M> { + phantom: PhantomData<(&'d mut T, M)>, at_cmd_config: Option, rx_timeout_config: Option, } -impl<'d, T> UartTx<'d, T> +impl<'d, T, M> UartTx<'d, T, M> where T: Instance, + M: Mode, { - // if we want to implement a standalone UartTx, - // uncomment below and take care of the configuration - // pub fn new(_uart: impl Peripheral

+ 'd) -> Self { - // Self::new_inner() - // } - fn new_inner() -> Self { Self { phantom: PhantomData, @@ -383,16 +384,11 @@ where } } -impl<'d, T> UartRx<'d, T> +impl<'d, T, M> UartRx<'d, T, M> where T: Instance, + M: Mode, { - // if we want to implement a standalone UartRx, - // uncomment below and take care of the configuration - // pub fn new(_uart: impl Peripheral

+ 'd) -> Self { - // Self::new_inner() - // } - fn new_inner() -> Self { Self { phantom: PhantomData, @@ -446,16 +442,42 @@ where } } -impl<'d, T> Uart<'d, T> +impl<'d, T> Uart<'d, T, Blocking> where T: Instance + 'd, { - /// Create a new UART instance with defaults + /// Create a new UART instance with configuration options in [`Blocking`] + /// mode. pub fn new_with_config

( + uart: impl Peripheral

+ 'd, + config: Config, + pins: Option

, + clocks: &Clocks, + interrupt: Option, + ) -> Self + where + P: UartPins, + { + Self::new_with_config_inner(uart, config, pins, clocks, interrupt) + } + + /// Create a new UART instance with defaults in [`Blocking`] mode. + pub fn new(uart: impl Peripheral

+ 'd, clocks: &Clocks) -> Self { + Self::new_inner(uart, clocks) + } +} + +impl<'d, T, M> Uart<'d, T, M> +where + T: Instance + 'd, + M: Mode, +{ + fn new_with_config_inner

( _uart: impl Peripheral

+ 'd, config: Config, mut pins: Option

, clocks: &Clocks, + interrupt: Option, ) -> Self where P: UartPins, @@ -483,21 +505,30 @@ where serial.change_parity(config.parity); serial.change_stop_bits(config.stop_bits); + if let Some(interrupt) = interrupt { + unsafe { + crate::interrupt::bind_interrupt(T::interrupt(), interrupt.handler()); + crate::interrupt::enable(T::interrupt(), interrupt.priority()).unwrap(); + } + } + serial } - /// Create a new UART instance with defaults - pub fn new(uart: impl Peripheral

+ 'd, clocks: &Clocks) -> Self { - use crate::gpio::*; - // not real, just to satify the type - type Pins<'a> = TxRxPins<'a, GpioPin, 2>, GpioPin, 0>>; - Self::new_with_config(uart, Default::default(), None::>, clocks) + fn new_inner(uart: impl Peripheral

+ 'd, clocks: &Clocks) -> Self { + Self::new_with_config_inner( + uart, + Default::default(), + None::>, + clocks, + None, + ) } /// Split the Uart into a transmitter and receiver, which is /// particularly useful when having two tasks correlating to /// transmitting and receiving. - pub fn split(self) -> (UartTx<'d, T>, UartRx<'d, T>) { + pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) { (self.tx, self.rx) } @@ -996,6 +1027,7 @@ where pub trait Instance { fn register_block() -> &'static RegisterBlock; fn uart_number() -> usize; + fn interrupt() -> Interrupt; fn disable_tx_interrupts() { Self::register_block().int_clr().write(|w| { @@ -1144,6 +1176,11 @@ macro_rules! impl_instance { $num } + #[inline(always)] + fn interrupt() -> Interrupt { + Interrupt::$inst + } + fn tx_signal() -> OutputSignal { OutputSignal::$txd } @@ -1177,9 +1214,10 @@ impl_instance!(UART1, 1, U1TXD, U1RXD, U1CTS, U1RTS, Uart1); impl_instance!(UART2, 2, U2TXD, U2RXD, U2CTS, U2RTS, Uart2); #[cfg(feature = "ufmt")] -impl ufmt_write::uWrite for Uart<'_, T> +impl ufmt_write::uWrite for Uart<'_, T, M> where T: Instance, + M: Mode, { type Error = Error; @@ -1195,9 +1233,10 @@ where } #[cfg(feature = "ufmt")] -impl ufmt_write::uWrite for UartTx<'_, T> +impl ufmt_write::uWrite for UartTx<'_, T, M> where T: Instance, + M: Mode, { type Error = Error; @@ -1208,9 +1247,10 @@ where } } -impl core::fmt::Write for Uart<'_, T> +impl core::fmt::Write for Uart<'_, T, M> where T: Instance, + M: Mode, { #[inline] fn write_str(&mut self, s: &str) -> core::fmt::Result { @@ -1218,9 +1258,10 @@ where } } -impl core::fmt::Write for UartTx<'_, T> +impl core::fmt::Write for UartTx<'_, T, M> where T: Instance, + M: Mode, { #[inline] fn write_str(&mut self, s: &str) -> core::fmt::Result { @@ -1231,9 +1272,10 @@ where } #[cfg(feature = "embedded-hal-02")] -impl embedded_hal_02::serial::Write for Uart<'_, T> +impl embedded_hal_02::serial::Write for Uart<'_, T, M> where T: Instance, + M: Mode, { type Error = Error; @@ -1247,9 +1289,10 @@ where } #[cfg(feature = "embedded-hal-02")] -impl embedded_hal_02::serial::Write for UartTx<'_, T> +impl embedded_hal_02::serial::Write for UartTx<'_, T, M> where T: Instance, + M: Mode, { type Error = Error; @@ -1263,9 +1306,10 @@ where } #[cfg(feature = "embedded-hal-02")] -impl embedded_hal_02::serial::Read for Uart<'_, T> +impl embedded_hal_02::serial::Read for Uart<'_, T, M> where T: Instance, + M: Mode, { type Error = Error; @@ -1275,9 +1319,10 @@ where } #[cfg(feature = "embedded-hal-02")] -impl embedded_hal_02::serial::Read for UartRx<'_, T> +impl embedded_hal_02::serial::Read for UartRx<'_, T, M> where T: Instance, + M: Mode, { type Error = Error; @@ -1287,24 +1332,25 @@ where } #[cfg(feature = "embedded-hal")] -impl embedded_hal_nb::serial::ErrorType for Uart<'_, T> { +impl embedded_hal_nb::serial::ErrorType for Uart<'_, T, M> { type Error = Error; } #[cfg(feature = "embedded-hal")] -impl embedded_hal_nb::serial::ErrorType for UartTx<'_, T> { +impl embedded_hal_nb::serial::ErrorType for UartTx<'_, T, M> { type Error = Error; } #[cfg(feature = "embedded-hal")] -impl embedded_hal_nb::serial::ErrorType for UartRx<'_, T> { +impl embedded_hal_nb::serial::ErrorType for UartRx<'_, T, M> { type Error = Error; } #[cfg(feature = "embedded-hal")] -impl embedded_hal_nb::serial::Read for Uart<'_, T> +impl embedded_hal_nb::serial::Read for Uart<'_, T, M> where T: Instance, + M: Mode, { fn read(&mut self) -> nb::Result { self.read_byte() @@ -1312,9 +1358,10 @@ where } #[cfg(feature = "embedded-hal")] -impl embedded_hal_nb::serial::Read for UartRx<'_, T> +impl embedded_hal_nb::serial::Read for UartRx<'_, T, M> where T: Instance, + M: Mode, { fn read(&mut self) -> nb::Result { self.read_byte() @@ -1322,9 +1369,10 @@ where } #[cfg(feature = "embedded-hal")] -impl embedded_hal_nb::serial::Write for Uart<'_, T> +impl embedded_hal_nb::serial::Write for Uart<'_, T, M> where T: Instance, + M: Mode, { fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { self.write_byte(word) @@ -1336,9 +1384,10 @@ where } #[cfg(feature = "embedded-hal")] -impl embedded_hal_nb::serial::Write for UartTx<'_, T> +impl embedded_hal_nb::serial::Write for UartTx<'_, T, M> where T: Instance, + M: Mode, { fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { self.write_byte(word) @@ -1350,24 +1399,25 @@ where } #[cfg(feature = "embedded-io")] -impl embedded_io::ErrorType for Uart<'_, T> { +impl embedded_io::ErrorType for Uart<'_, T, M> { type Error = Error; } #[cfg(feature = "embedded-io")] -impl embedded_io::ErrorType for UartTx<'_, T> { +impl embedded_io::ErrorType for UartTx<'_, T, M> { type Error = Error; } #[cfg(feature = "embedded-io")] -impl embedded_io::ErrorType for UartRx<'_, T> { +impl embedded_io::ErrorType for UartRx<'_, T, M> { type Error = Error; } #[cfg(feature = "embedded-io")] -impl embedded_io::Read for Uart<'_, T> +impl embedded_io::Read for Uart<'_, T, M> where T: Instance, + M: Mode, { fn read(&mut self, buf: &mut [u8]) -> Result { self.rx.read(buf) @@ -1375,9 +1425,10 @@ where } #[cfg(feature = "embedded-io")] -impl embedded_io::Read for UartRx<'_, T> +impl embedded_io::Read for UartRx<'_, T, M> where T: Instance, + M: Mode, { fn read(&mut self, buf: &mut [u8]) -> Result { if buf.len() == 0 { @@ -1393,9 +1444,10 @@ where } #[cfg(feature = "embedded-io")] -impl embedded_io::Write for Uart<'_, T> +impl embedded_io::Write for Uart<'_, T, M> where T: Instance, + M: Mode, { fn write(&mut self, buf: &[u8]) -> Result { self.tx.write(buf) @@ -1407,9 +1459,10 @@ where } #[cfg(feature = "embedded-io")] -impl embedded_io::Write for UartTx<'_, T> +impl embedded_io::Write for UartTx<'_, T, M> where T: Instance, + M: Mode, { fn write(&mut self, buf: &[u8]) -> Result { self.write_bytes(buf) @@ -1430,15 +1483,15 @@ where #[cfg(feature = "async")] mod asynch { - use core::{marker::PhantomData, task::Poll}; + use core::task::Poll; use cfg_if::cfg_if; use embassy_sync::waitqueue::AtomicWaker; use enumset::{EnumSet, EnumSetType}; - use procmacros::interrupt; + use procmacros::handler; - use super::{Error, Instance}; - use crate::uart::{RegisterBlock, Uart, UartRx, UartTx, UART_FIFO_SIZE}; + use super::*; + use crate::Async; cfg_if! { if #[cfg(all(uart0, uart1, uart2))] { @@ -1633,7 +1686,50 @@ mod asynch { } } - impl Uart<'_, T> + impl<'d, T> Uart<'d, T, Async> + where + T: Instance + 'd, + { + /// Create a new UART instance with configuration options in [`Async`] + /// mode. + pub fn new_async_with_config

( + uart: impl Peripheral

+ 'd, + config: Config, + pins: Option

, + clocks: &Clocks, + ) -> Self + where + P: UartPins, + { + Self::new_with_config_inner( + uart, + config, + pins, + clocks, + Some(match T::uart_number() { + #[cfg(uart0)] + 0 => uart0, + #[cfg(uart1)] + 1 => uart1, + #[cfg(uart2)] + 2 => uart2, + _ => unreachable!(), + }), + ) + } + + /// Create a new UART instance with defaults in [`Async`] mode. + pub fn new_async(uart: impl Peripheral

+ 'd, clocks: &Clocks) -> Self { + Self::new_async_with_config( + uart, + Default::default(), + None::>, + clocks, + ) + } + } + + impl Uart<'_, T, Async> where T: Instance, { @@ -1651,7 +1747,7 @@ mod asynch { } } - impl UartTx<'_, T> + impl UartTx<'_, T, Async> where T: Instance, { @@ -1690,7 +1786,7 @@ mod asynch { } } - impl UartRx<'_, T> + impl UartRx<'_, T, Async> where T: Instance, { @@ -1747,7 +1843,7 @@ mod asynch { } } - impl embedded_io_async::Read for Uart<'_, T> + impl embedded_io_async::Read for Uart<'_, T, Async> where T: Instance, { @@ -1759,7 +1855,7 @@ mod asynch { } } - impl embedded_io_async::Read for UartRx<'_, T> + impl embedded_io_async::Read for UartRx<'_, T, Async> where T: Instance, { @@ -1771,7 +1867,7 @@ mod asynch { } } - impl embedded_io_async::Write for Uart<'_, T> + impl embedded_io_async::Write for Uart<'_, T, Async> where T: Instance, { @@ -1784,7 +1880,7 @@ mod asynch { } } - impl embedded_io_async::Write for UartTx<'_, T> + impl embedded_io_async::Write for UartTx<'_, T, Async> where T: Instance, { @@ -1821,8 +1917,8 @@ mod asynch { } #[cfg(uart0)] - #[interrupt] - fn UART0() { + #[handler] + fn uart0() { let uart = unsafe { &*crate::peripherals::UART0::ptr() }; let (rx, tx) = intr_handler(uart); if rx { @@ -1834,8 +1930,8 @@ mod asynch { } #[cfg(uart1)] - #[interrupt] - fn UART1() { + #[handler] + fn uart1() { let uart = unsafe { &*crate::peripherals::UART1::ptr() }; let (rx, tx) = intr_handler(uart); if rx { @@ -1847,8 +1943,8 @@ mod asynch { } #[cfg(uart2)] - #[interrupt] - fn UART2() { + #[handler] + fn uart2() { let uart = unsafe { &*crate::peripherals::UART2::ptr() }; let (rx, tx) = intr_handler(uart); if rx { diff --git a/examples/src/bin/advanced_serial.rs b/examples/src/bin/advanced_serial.rs index 1fbf46dfacf..e6a6aa2a0c1 100644 --- a/examples/src/bin/advanced_serial.rs +++ b/examples/src/bin/advanced_serial.rs @@ -49,7 +49,7 @@ fn main() -> ! { io.pins.gpio5.into_floating_input(), ); - let mut serial1 = Uart::new_with_config(peripherals.UART1, config, Some(pins), &clocks); + let mut serial1 = Uart::new_with_config(peripherals.UART1, config, Some(pins), &clocks, None); let delay = Delay::new(&clocks); diff --git a/examples/src/bin/embassy_serial.rs b/examples/src/bin/embassy_serial.rs index d5867bf3c06..2bfe840a70c 100644 --- a/examples/src/bin/embassy_serial.rs +++ b/examples/src/bin/embassy_serial.rs @@ -20,6 +20,7 @@ use esp_hal::{ prelude::*, timer::TimerGroup, uart::{config::AtCmdConfig, Uart, UartRx, UartTx}, + Async, }; use static_cell::make_static; @@ -29,7 +30,10 @@ const READ_BUF_SIZE: usize = 64; const AT_CMD: u8 = 0x04; #[embassy_executor::task] -async fn writer(mut tx: UartTx<'static, UART0>, signal: &'static Signal) { +async fn writer( + mut tx: UartTx<'static, UART0, Async>, + signal: &'static Signal, +) { use core::fmt::Write; embedded_io_async::Write::write( &mut tx, @@ -47,7 +51,10 @@ async fn writer(mut tx: UartTx<'static, UART0>, signal: &'static Signal, signal: &'static Signal) { +async fn reader( + mut rx: UartRx<'static, UART0, Async>, + signal: &'static Signal, +) { const MAX_BUFFER_SIZE: usize = 10 * READ_BUF_SIZE + 16; let mut rbuf: [u8; MAX_BUFFER_SIZE] = [0u8; MAX_BUFFER_SIZE]; @@ -76,7 +83,7 @@ async fn main(spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); embassy::init(&clocks, timg0); - let mut uart0 = Uart::new(peripherals.UART0, &clocks); + let mut uart0 = Uart::new_async(peripherals.UART0, &clocks); uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); uart0 .set_rx_fifo_full_threshold(READ_BUF_SIZE as u16) diff --git a/examples/src/bin/lp_core_uart.rs b/examples/src/bin/lp_core_uart.rs index 8834cd7f755..16d0bb9e03e 100644 --- a/examples/src/bin/lp_core_uart.rs +++ b/examples/src/bin/lp_core_uart.rs @@ -50,7 +50,7 @@ fn main() -> ! { io.pins.gpio7.into_floating_input(), ); - let mut uart1 = Uart::new_with_config(peripherals.UART1, config, Some(pins), &clocks); + let mut uart1 = Uart::new_with_config(peripherals.UART1, config, Some(pins), &clocks, None); // Set up (LP) UART: let lp_tx = io.pins.gpio5.into_low_power().into_push_pull_output(); diff --git a/examples/src/bin/serial_interrupts.rs b/examples/src/bin/serial_interrupts.rs index 1f847420dbc..3ebc3f50b66 100644 --- a/examples/src/bin/serial_interrupts.rs +++ b/examples/src/bin/serial_interrupts.rs @@ -20,10 +20,11 @@ use esp_hal::{ prelude::*, timer::TimerGroup, uart::{config::AtCmdConfig, Uart}, + Blocking, }; use nb::block; -static SERIAL: Mutex>>> = Mutex::new(RefCell::new(None)); +static SERIAL: Mutex>>> = Mutex::new(RefCell::new(None)); #[entry] fn main() -> ! { diff --git a/hil-test/tests/uart.rs b/hil-test/tests/uart.rs index a06c11948ab..54756672c96 100644 --- a/hil-test/tests/uart.rs +++ b/hil-test/tests/uart.rs @@ -21,11 +21,12 @@ use esp_hal::{ TxRxPins, Uart, }, + Blocking, }; use nb::block; struct Context { - uart: Uart<'static, UART0>, + uart: Uart<'static, UART0, Blocking>, } impl Context { @@ -45,7 +46,7 @@ impl Context { stop_bits: StopBits::STOP1, }; - let uart = Uart::new_with_config(peripherals.UART0, config, Some(pins), &clocks); + let uart = Uart::new_with_config(peripherals.UART0, config, Some(pins), &clocks, None); Context { uart } } From 1b2dab1dff7abfaae20fc87e7762a8ef0c835f7f Mon Sep 17 00:00:00 2001 From: Anthony Grondin <104731965+AnthonyGrondin@users.noreply.github.com> Date: Thu, 21 Mar 2024 18:10:15 -0400 Subject: [PATCH 10/16] Add missing `#[doc(hidden)]` attributes for embassy proc macros (#1302) Fixes https://github.com/esp-rs/esp-hal/issues/1233 --- esp-hal-procmacros/src/embassy.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esp-hal-procmacros/src/embassy.rs b/esp-hal-procmacros/src/embassy.rs index c0411330efe..0dd8316b99d 100644 --- a/esp-hal-procmacros/src/embassy.rs +++ b/esp-hal-procmacros/src/embassy.rs @@ -79,11 +79,13 @@ pub(crate) mod main { let out = &f.sig.output; let result = quote! { + #[doc(hidden)] #[::embassy_executor::task()] async fn __embassy_main(#fargs) #out { #f_body } + #[doc(hidden)] unsafe fn __make_static(t: &mut T) -> &'static mut T { ::core::mem::transmute(t) } From d50290e9dd45247d8a791efad161d49118ffec48 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 22 Mar 2024 10:37:32 +0100 Subject: [PATCH 11/16] =?UTF-8?q?Fix=20I=C2=B2C=20frequency=20for=20esp32?= =?UTF-8?q?=20and=20esp32s2.=20(#1333)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ghislain MARY --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/clock/mod.rs | 2 +- esp-hal/src/i2c.rs | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index bf1ffa2a413..3c4add5db50 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixing `esp-wifi` + `TRNG` issue on `ESP32-S2` (#1272) - Fixed core1 startup using the wrong stack on the esp32 and esp32s3 (#1286). - ESP32: Apply fix for Errata 3.6 in all the places necessary. (#1315) +- ESP32 & ESP32-S2: Fix I²C frequency (#1306) ### Changed diff --git a/esp-hal/src/clock/mod.rs b/esp-hal/src/clock/mod.rs index d8a802a1769..44242fd369d 100644 --- a/esp-hal/src/clock/mod.rs +++ b/esp-hal/src/clock/mod.rs @@ -398,7 +398,7 @@ impl<'d> ClockControl<'d> { cpu_clock: cpu_clock_speed.frequency(), apb_clock: HertzU32::MHz(80), xtal_clock: HertzU32::MHz(40), - i2c_clock: HertzU32::MHz(40), + i2c_clock: HertzU32::MHz(80), // The docs are unclear here. pwm_clock seems to be tied to clocks.apb_clock // while simultaneously being fixed at 160 MHz. // Testing showed 160 MHz to be correct for current clock configurations. diff --git a/esp-hal/src/i2c.rs b/esp-hal/src/i2c.rs index b0caf4347dd..f23f029b8f9 100644 --- a/esp-hal/src/i2c.rs +++ b/esp-hal/src/i2c.rs @@ -689,7 +689,9 @@ pub trait Instance { // Configure frequency #[cfg(esp32)] self.set_frequency(clocks.i2c_clock.convert(), frequency, timeout); - #[cfg(not(esp32))] + #[cfg(esp32s2)] + self.set_frequency(clocks.apb_clock.convert(), frequency, timeout); + #[cfg(not(any(esp32, esp32s2)))] self.set_frequency(clocks.xtal_clock.convert(), frequency, timeout); self.update_config(); From 3efdbe9420e5c32d11c105c544bc4e6ac4eb64c1 Mon Sep 17 00:00:00 2001 From: Sergio Gasquez Arcos Date: Fri, 22 Mar 2024 16:09:20 +0100 Subject: [PATCH 12/16] docs: Fix i2c pins (#1340) --- examples/src/bin/i2c_display.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src/bin/i2c_display.rs b/examples/src/bin/i2c_display.rs index bc3c06aa588..5b3aa91877e 100644 --- a/examples/src/bin/i2c_display.rs +++ b/examples/src/bin/i2c_display.rs @@ -4,8 +4,8 @@ //! display (via I2C) //! //! The following wiring is assumed: -//! - SDA => GPIO1 -//! - SCL => GPIO2 +//! - SDA => GPIO4 +//! - SCL => GPIO5 //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 //% FEATURES: embedded-hal-02 From 8da8425907e58a36e475e72b8d78f9d2d3ebe9a1 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Fri, 22 Mar 2024 17:11:20 +0000 Subject: [PATCH 13/16] Update `README`s, housekeeping (#1339) * Remove patches and just use git dependency for PACs instead * Various `README.md` normalization/updates for simpler packages * Update `README.md` for `esp-hal` and `esp-lp-hal` * Update repo-level `README.md` --- README.md | 89 ++++++++---------------------------- esp-build/README.md | 13 ++++-- esp-hal-procmacros/README.md | 14 +++--- esp-hal-smartled/README.md | 13 +++--- esp-hal/Cargo.toml | 26 ++++------- esp-hal/README.md | 78 +++++++++++++++---------------- esp-lp-hal/README.md | 48 ++++++------------- esp-metadata/README.md | 7 ++- esp-riscv-rt/README.md | 21 +++++---- examples/Cargo.toml | 10 ---- 10 files changed, 118 insertions(+), 201 deletions(-) diff --git a/README.md b/README.md index a9dd1d3c3ff..36571f66139 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,21 @@ # esp-hal -![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/esp-rs/esp-hal/ci.yml?label=CI&logo=github&style=flat-square) -![MIT/Apache-2.0 licensed](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue?style=flat-square) -[![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?label=join%20matrix&color=BEC5C9&logo=matrix&style=flat-square)](https://matrix.to/#/#esp-rs:matrix.org) +![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/esp-rs/esp-hal/ci.yml?labelColor=1C2C2E&label=CI&logo=github&style=flat-square) +![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/esp-rs/esp-hal/hil.yml?labelColor=1C2C2E&label=HIL&logo=github&style=flat-square&event=merge_group) +![MIT/Apache-2.0 licensed](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue?labelColor=1C2C2E&style=flat-square) +[![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?labelColor=1C2C2E&label=join%20matrix&color=BEC5C9&logo=matrix&style=flat-square)](https://matrix.to/#/#esp-rs:matrix.org) -**H**ardware **A**bstraction **L**ayer crates for the **ESP32**, **ESP32-C2/C3/C6**, **ESP32-H2**, **ESP32-P4**, and **ESP32-S2/S3** from Espressif. Additionally provides support for programming the low-power RISC-V cores found on the **ESP32-C6** and **ESP32-S2/S3**. +Bare-metal (`no_std`) hardware abstraction layer for Espressif devices. Currently supports, to varying degrees, the following devices: -These HALs are `no_std`; if you are looking for `std` support, please use [esp-idf-hal] instead. +- ESP32 Series: _ESP32_ +- ESP32-C Series: _ESP32-C2 (aka ESP8684), ESP32-C3 (aka ESP8685), ESP32-C6_ +- ESP32-H Series: _ESP32-H2_ +- ESP32-P Series: _ESP32-P4_ +- ESP32-S Series: _ESP32-S2, ESP32-S3_ + +Additionally provides limited support for programming the low-power RISC-V cores found on the _ESP32-C6_, _ESP32-S2_, and _ESP32-S3_ via the [esp-lp-hal] package. + +These packages are all `no_std`; if you are looking for `std` support, please use [esp-idf-svc] instead. If you have any questions, comments, or concerns, please [open an issue], [start a new discussion], or join us on [Matrix]. For additional information regarding any of the crates in this repository, please refer to the relevant crate's README. @@ -14,7 +23,8 @@ If you have any questions, comments, or concerns, please [open an issue], [start > > This project is still in the relatively early stages of development, and as such there should be no expectation of API stability. A significant number of peripherals currently have drivers implemented but have varying levels of functionality. For most basic tasks, this should be usable already, however some more advanced or uncommon features may not yet be implemented. -[esp-idf-hal]: https://github.com/esp-rs/esp-idf-hal +[esp-lp-hal]: https://github.com/esp-rs/esp-hal/tree/main/esp-lp-hal +[esp-idf-svc]: https://github.com/esp-rs/esp-idf-svc [open an issue]: https://github.com/esp-rs/esp-hal/issues/new [start a new discussion]: https://github.com/esp-rs/esp-hal/discussions/new [matrix]: https://matrix.to/#/#esp-rs:matrix.org @@ -23,10 +33,10 @@ If you have any questions, comments, or concerns, please [open an issue], [start For information relating to the development of Rust applications on ESP devices, please first read [The Rust on ESP Book]. -For information about the HAL and how to use it in your own projects, please refer to the documentation on [docs.rs] for the relevant chip. +For information about the HAL and how to use it in your own projects, please refer to the [documentation]. [The Rust on ESP Book]: https://esp-rs.github.io/book/ -[docs.rs]: https://docs.rs +[documentation]: https://docs.esp-rs.org/esp-hal/ ## Resources @@ -38,56 +48,7 @@ For information about the HAL and how to use it in your own projects, please ref ## Crates -### [esp-hal] - -Implements number of the traits defined in [embedded-hal](https://github.com/rust-embedded/embedded-hal) for various ESP devices. Full list of currently supported devices with basic information is in the table below. - -| Feature | Technical Reference Manual | Target | MSRV | -| :-----------: | :------------------------: | :-----------------------------: | :--------: | -| `esp32` | [ESP32] | `xtensa-esp32-none-elf` | ![esp] | -| `esp32c2` | [ESP32-C2] | `riscv32imc-unknown-none-elf` | ![stable] | -| `esp32c3` | [ESP32-C3] | `riscv32imc-unknown-none-elf` | ![stable] | -| `esp32c6` | [ESP32-C6] | `riscv32imac-unknown-none-elf` | ![stable] | -| `esp32h2` | [ESP32-H2] | `riscv32imac-unknown-none-elf` | ![stable] | -| `esp32p4` | [ESP32-P4] | `riscv32imafc-unknown-none-elf` | ![stable] | -| `esp32s2` | [ESP32-S2] | `xtensa-esp32s2-none-elf` | ![esp] | -| `esp32s3` | [ESP32-S3] | `xtensa-esp32s3-none-elf` | ![esp] | - -[esp-hal]: https://github.com/esp-rs/esp-hal/tree/main/esp-hal -[esp]: https://img.shields.io/badge/rustc-esp%201.74+-red.svg -[stable]: https://img.shields.io/badge/rustc-stable%201.76+-red.svg -[esp32]: https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf -[esp32-c2]: https://www.espressif.com/sites/default/files/documentation/esp8684_technical_reference_manual_en.pdf -[esp32-c3]: https://www.espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf -[esp32-c6]: https://www.espressif.com/sites/default/files/documentation/esp32-c6_technical_reference_manual_en.pdf -[esp32-h2]: https://www.espressif.com/sites/default/files/documentation/esp32-h2_technical_reference_manual_en.pdf -[esp32-p4]: https://www.espressif.com/sites/default/files/documentation/esp32-p4_technical_reference_manual_en.pdf -[esp32-s2]: https://www.espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf -[esp32-s3]: https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf - -### [esp-lp-hal] - -Implements a number of the traits defined in [embedded-hal](https://github.com/rust-embedded/embedded-hal) for the low-power (lp) RISC-V coprocessors found on the ESP32-C6, ESP32-S2, and ESP32-S3 from Espressif. The main idea is to have code running on lp core and putting the main core into sleep, making it more power-efficient. - - -| Crate | Documentation | Targets | -| :----------: | :-----------------------: | :-----------------------------------------------------------: | -| [esp-lp-hal] | N/A (_Not yet published_) | `riscv32imc-unknown-none-elf`, `riscv32imac-unknown-none-elf` | - - -[esp-lp-hal]: https://github.com/esp-rs/esp-hal/tree/main/esp-lp-hal - -### [esp-hal-procmacros] - -Procedural macros for use with the esp-hal family of HAL packages. - -[esp-hal-procmacros]: https://github.com/esp-rs/esp-hal/tree/main/esp-hal-procmacros - -### [esp-riscv-rt] - -Minimal runtime / startup for RISC-V CPUs from Espressif. - -[esp-riscv-rt]: https://github.com/esp-rs/esp-hal/tree/main/esp-riscv-rt +This repository is home to a number of different packages; for more information regarding a particular package, please refer to its `README.md` and/or documentation. ## Ancillary Crates @@ -113,18 +74,6 @@ There are a number of other crates within the [esp-rs organization] which can be [embedded-storage]: https://github.com/rust-embedded-community/embedded-storage [esp-wifi]: https://github.com/esp-rs/esp-wifi -## Git Hooks - -We provide a simple `pre-commit` hook to verify the formatting of each package prior to committing changes. We _strongly_ encourage use of this git hook. - -The hook can be enabled by copying it in to the `.git/hooks/` directory: - -```bash -cp pre-commit .git/hooks/pre-commit -``` - -When using this hook, you can choose to ignore its failure on a per-commit basis by committing with the `--no-verify` flag; however, you will need to be sure that all packages are formatted when submitting a pull request. - ## License Licensed under either of: diff --git a/esp-build/README.md b/esp-build/README.md index 94d9c4dbf7f..3dfcc3eb5e1 100644 --- a/esp-build/README.md +++ b/esp-build/README.md @@ -1,11 +1,14 @@ # esp-build -[![Crates.io](https://img.shields.io/crates/v/esp-build?color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp-build) -[![docs.rs](https://img.shields.io/docsrs/esp-build?color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp-build) -![MSRV](https://img.shields.io/badge/MSRV-1.60-blue?style=flat-square) -![Crates.io](https://img.shields.io/crates/l/esp-build?style=flat-square) +[![Crates.io](https://img.shields.io/crates/v/esp-build?labelColor=1C2C2E&color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp-build) +[![docs.rs](https://img.shields.io/docsrs/esp-build?labelColor=1C2C2E&color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp-build) +![MSRV](https://img.shields.io/badge/MSRV-1.60-blue?labelColor=1C2C2E&style=flat-square) +![Crates.io](https://img.shields.io/crates/l/esp-build?labelColor=1C2C2E&style=flat-square) +[![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?label=join%20matrix&labelColor=1C2C2E&color=BEC5C9&logo=matrix&style=flat-square)](https://matrix.to/#/#esp-rs:matrix.org) -Build utilities for `esp-hal`. +Build utilities for use with `esp-hal` and other related packages, intended for use in [build scripts]. This package is still quite minimal, but provides: + +[build scripts]: https://doc.rust-lang.org/cargo/reference/build-scripts.html ## [Documentation](https://docs.rs/crate/esp-build) diff --git a/esp-hal-procmacros/README.md b/esp-hal-procmacros/README.md index 82877254743..c263479e5a0 100644 --- a/esp-hal-procmacros/README.md +++ b/esp-hal-procmacros/README.md @@ -2,21 +2,21 @@ [![Crates.io](https://img.shields.io/crates/v/esp-hal-procmacros?labelColor=1C2C2E&color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp-hal-procmacros) [![docs.rs](https://img.shields.io/docsrs/esp-hal-procmacros?labelColor=1C2C2E&color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp-hal-procmacros) +![MSRV](https://img.shields.io/badge/MSRV-1.76-blue?labelColor=1C2C2E&style=flat-square) ![Crates.io](https://img.shields.io/crates/l/esp-hal-procmacros?labelColor=1C2C2E&style=flat-square) [![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?label=join%20matrix&labelColor=1C2C2E&color=BEC5C9&logo=matrix&style=flat-square)](https://matrix.to/#/#esp-rs:matrix.org) -Procedural macros for use with the `esp-hal` family of HAL packages. - -Provides macros for: - -- Placing statics and functions into RAM -- Marking interrupt handlers -- Automatically creating an `embassy` executor instance and spawning the defined entry point +Procedural macros for use with `esp-hal` and other related packages. ## [Documentation] [documentation]: https://docs.rs/esp-hal-procmacros/ +## Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust 1.76 and up. It _might_ +compile with older versions but that may change in any new patch release. + ## License Licensed under either of: diff --git a/esp-hal-smartled/README.md b/esp-hal-smartled/README.md index 460eec967be..ee72ac118ae 100644 --- a/esp-hal-smartled/README.md +++ b/esp-hal-smartled/README.md @@ -2,21 +2,22 @@ [![Crates.io](https://img.shields.io/crates/v/esp-hal-smartled?labelColor=1C2C2E&color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp-hal-smartled) [![docs.rs](https://img.shields.io/docsrs/esp-hal-smartled?labelColor=1C2C2E&color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp-hal-smartled) +![MSRV](https://img.shields.io/badge/MSRV-1.76-blue?labelColor=1C2C2E&style=flat-square) ![Crates.io](https://img.shields.io/crates/l/esp-hal-smartled?labelColor=1C2C2E&style=flat-square) [![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?label=join%20matrix&labelColor=1C2C2E&color=BEC5C9&logo=matrix&style=flat-square)](https://matrix.to/#/#esp-rs:matrix.org) -This adapter allows for the use of an RMT output channel to easily interact with RGB LEDs and use the convenience functions of the [`smart-leds`](https://crates.io/crates/smart-leds) crate. +Allows for the use of an RMT output channel to easily interact with RGB LEDs and use the convenience functions of the [smart-leds] crate. + +[smart-leds]: https://crates.io/crates/smart-leds ## [Documentation] [documentation]: https://docs.rs/esp-hal-smartled/ -## Usage - -### `defmt` Feature +## Minimum Supported Rust Version (MSRV) -Please note that `defmt` does _not_ provide MSRV guarantees with releases, and as such we are not able to make any MSRV guarantees when this feature is enabled. For more information refer to the MSRV section of `defmt`'s README: -https://github.com/knurling-rs/defmt?tab=readme-ov-file#msrv +This crate is guaranteed to compile on stable Rust 1.76 and up. It _might_ +compile with older versions but that may change in any new patch release. ## License diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml index 48e03e9791a..ee265c80695 100644 --- a/esp-hal/Cargo.toml +++ b/esp-hal/Cargo.toml @@ -52,14 +52,14 @@ xtensa-lx = { version = "0.9.0", optional = true } # IMPORTANT: # Each supported device MUST have its PAC included below along with a # corresponding feature. -esp32 = { version = "0.29.0", features = ["critical-section"], optional = true } -esp32c2 = { version = "0.18.0", features = ["critical-section"], optional = true } -esp32c3 = { version = "0.21.0", features = ["critical-section"], optional = true } -esp32c6 = { version = "0.12.0", features = ["critical-section"], optional = true } -esp32h2 = { version = "0.8.0", features = ["critical-section"], optional = true } -esp32p4 = { version = "0.1.0", features = ["critical-section"], optional = true } -esp32s2 = { version = "0.20.0", features = ["critical-section"], optional = true } -esp32s3 = { version = "0.24.0", features = ["critical-section"], optional = true } +esp32 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } +esp32c2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } +esp32c3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } +esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } +esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } +esp32p4 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } +esp32s2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } +esp32s3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } [target.'cfg(target_arch = "riscv32")'.dependencies] esp-riscv-rt = { version = "0.7.0", optional = true, path = "../esp-riscv-rt" } @@ -228,13 +228,3 @@ ci = [ [lints.clippy] mixed_attributes_style = "allow" - -[patch.crates-io] -esp32 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } -esp32s2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } -esp32s3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } -esp32c2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } -esp32c3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } -esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } -esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } -esp32p4 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } diff --git a/esp-hal/README.md b/esp-hal/README.md index c87c8fd6eb3..0bac1874fdf 100644 --- a/esp-hal/README.md +++ b/esp-hal/README.md @@ -1,59 +1,55 @@ # esp-hal [![Crates.io](https://img.shields.io/crates/v/esp-hal?labelColor=1C2C2E&color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp-hal) +[![docs.rs](https://img.shields.io/docsrs/esp-hal?labelColor=1C2C2E&color=C96329&logo=rust&style=flat-square)](https://docs.esp-rs.org/esp-hal) +![MSRV](https://img.shields.io/badge/MSRV-1.76-blue?labelColor=1C2C2E&style=flat-square) ![Crates.io](https://img.shields.io/crates/l/esp-hal?labelColor=1C2C2E&style=flat-square) [![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?label=join%20matrix&labelColor=1C2C2E&color=BEC5C9&logo=matrix&style=flat-square)](https://matrix.to/#/#esp-rs:matrix.org) -The `esp-hal` package aims to provide a safe, idiomatic Hardware Abstraction Layer (HAL) for the entire family of ESP32 devices from Espressif. +Bare-metal (`no_std`) hardware abstraction layer for Espressif devices. -This package implements both blocking and, when able, asynchronous drivers for the various peripherals. At this time the blocking APIs are used by default, with all asynchronous functionality gated behind the `async` feature. See the package documentation for more information on its features. +Implements a number of blocking and, where applicable, async traits from the various packages in the [embedded-hal] repository. -Most traits defined by the [embedded-hal] family of packages are implemented as applicable. +For help getting started with this HAL, please refer to [The Rust on ESP Book] and the [documentation]. [embedded-hal]: https://github.com/rust-embedded/embedded-hal +[the rust on esp book]: https://docs.esp-rs.org/book/ ## [Documentation] [documentation]: https://docs.esp-rs.org/esp-hal/ -## Usage - -Before using `esp-hal`, ensure that you have configured your [development environment] correctly, and the [required tooling] has been installed. - -When starting a new project using `esp-hal`, we strongly recommend you generate a project skeleton using [cargo-generate] and [esp-template]. This will take much of the guesswork out of the process and give you a starting point to build an application from. - -Much of the functionality available is feature-gated, so be sure to refer to the documentation to read about all available Cargo features. - -[development environment]: https://esp-rs.github.io/book/installation/index.html -[required tooling]: https://esp-rs.github.io/book/tooling/espflash.html -[cargo-generate]: https://github.com/cargo-generate/cargo-generate/ -[esp-template]: https://github.com/esp-rs/esp-template/ - -### `defmt` Feature - -Please note that `defmt` does _not_ provide MSRV guarantees with releases, and as such we are not able to make any MSRV guarantees when this feature is enabled. For more information refer to the MSRV section of `defmt`'s README: -https://github.com/knurling-rs/defmt?tab=readme-ov-file#msrv - -### Supporting Packages - -A number of additional packages are available which add additional functionality beyond the HAL. - -Within this repository, the [esp-lp-hal] package provides support for the (ultra-)low-power RISC-V coprocessors found aboard the ESP32-C6, ESP32-S2, and ESP32-S3. - -There is also the [esp-wifi] package, which provides support for Bluetooth and Wi-Fi. - -For additional libraries, you can check the [list of repositories] in the [esp-rs organization]. - -[esp-lp-hal]: ../esp-lp-hal/ -[esp-wifi]: https://github.com/esp-rs/esp-wifi -[list of repositories]: https://github.com/orgs/esp-rs/repositories -[esp-rs organization]: https://github.com/esp-rs - -## Examples - -Examples demonstrating the use of various peripherals and features of the HAL are available in the [examples] package. - -[examples]: ../examples/ +## Supported Devices + +| Chip | Datasheet | Technical Reference Manual | Target | +| :------: | :----------------------: | :------------------------: | :----------------------------: | +| ESP32 | [ESP32][32-datasheet] | [ESP32][32-trm] | `xtensa-esp32-none-elf` | +| ESP32-C2 | [ESP32-C2][c2-datasheet] | [ESP32-C2][c2-trm] | `riscv32imc-unknown-none-elf` | +| ESP32-C3 | [ESP32-C3][c3-datasheet] | [ESP32-C3][c3-trm] | `riscv32imc-unknown-none-elf` | +| ESP32-C6 | [ESP32-C6][c6-datasheet] | [ESP32-C6][c6-trm] | `riscv32imac-unknown-none-elf` | +| ESP32-H2 | [ESP32-H2][h2-datasheet] | [ESP32-H2][h2-trm] | `riscv32imac-unknown-none-elf` | +| ESP32-S2 | [ESP32-S2][s2-datasheet] | [ESP32-S2][s2-trm] | `xtensa-esp32s2-none-elf` | +| ESP32-S3 | [ESP32-S3][s3-datasheet] | [ESP32-S3][s3-trm] | `xtensa-esp32s3-none-elf` | + +[32-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf +[c2-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp8684_datasheet_en.pdf +[c3-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf +[c6-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf +[h2-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf +[s2-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf +[s3-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf +[32-trm]: https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf +[c2-trm]: https://www.espressif.com/sites/default/files/documentation/esp8684_technical_reference_manual_en.pdf +[c3-trm]: https://www.espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf +[c6-trm]: https://www.espressif.com/sites/default/files/documentation/esp32-c6_technical_reference_manual_en.pdf +[h2-trm]: https://www.espressif.com/sites/default/files/documentation/esp32-h2_technical_reference_manual_en.pdf +[s2-trm]: https://www.espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf +[s3-trm]: https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf + +## Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust 1.76 and up. It _might_ +compile with older versions but that may change in any new patch release. ## License diff --git a/esp-lp-hal/README.md b/esp-lp-hal/README.md index 168a20ea961..e3057e34d76 100644 --- a/esp-lp-hal/README.md +++ b/esp-lp-hal/README.md @@ -2,23 +2,18 @@ [![Crates.io](https://img.shields.io/crates/v/esp-lp-hal?labelColor=1C2C2E&color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp-lp-hal) [![docs.rs](https://img.shields.io/docsrs/esp-lp-hal?labelColor=1C2C2E&color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp-lp-hal) +![MSRV](https://img.shields.io/badge/MSRV-1.76-blue?labelColor=1C2C2E&style=flat-square) ![Crates.io](https://img.shields.io/crates/l/esp-lp-hal?labelColor=1C2C2E&style=flat-square) [![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?label=join%20matrix&labelColor=1C2C2E&color=BEC5C9&logo=matrix&style=flat-square)](https://matrix.to/#/#esp-rs:matrix.org) -`no_std` HAL for the low-power RISC-V coprocessors found on the ESP32-C6, ESP32-S2, and ESP32-S3 from Espressif. +Bare-metal (`no_std`) hardware abstraction layer for the low-power RISC-V coprocessors found in the ESP32-C6, ESP32-S2, and ESP32-S3 from Espressif. -Implements a number of the traits defined in [embedded-hal](https://github.com/rust-embedded/embedded-hal). +Implements a number of blocking and, where applicable, async traits from the various packages in the [embedded-hal] repository. -These devices uses the RISC-V ISA, which is officially supported by the Rust compiler via the `riscv32imc-unknown-none-elf` and `riscv32imac-unknown-none-elf` targets. +For help getting started with this HAL, please refer to [The Rust on ESP Book] and the [documentation]. -Please refer to the documentation for more information. - -[c6-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf -[s2-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf -[s3-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf -[c6-trm]: https://www.espressif.com/sites/default/files/documentation/esp32-c6_technical_reference_manual_en.pdf -[s2-trm]: https://www.espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf -[s3-trm]: https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf +[embedded-hal]: https://github.com/rust-embedded/embedded-hal +[the rust on esp book]: https://docs.esp-rs.org/book/ ## [Documentation] @@ -32,30 +27,17 @@ Please refer to the documentation for more information. | ESP32-S2 | [ESP32-S2][s2-datasheet] | [ESP32-S2][s2-trm] | `riscv32imc-unknown-none-elf` | | ESP32-S3 | [ESP32-S3][s3-datasheet] | [ESP32-S3][s3-trm] | `riscv32imc-unknown-none-elf` | -## Resources - -- [The Rust Programming Language](https://doc.rust-lang.org/book/) -- [The Embedded Rust Book](https://docs.rust-embedded.org/book/index.html) -- [The Rust on ESP Book](https://esp-rs.github.io/book/) -- Datasheets: - - [ESP32-C6](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) - - [ESP32-S2](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) - - [ESP32-S3](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) -- Technical Reference Manuals: - - [ESP32-C6](https://www.espressif.com/sites/default/files/documentation/esp32-c6_technical_reference_manual_en.pdf) - - [ESP32-S2](https://www.espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf) - - [ESP32-S3](https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf) - -## Getting Started - -### Installing the Rust Compiler Targets +[c6-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf +[s2-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf +[s3-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf +[c6-trm]: https://www.espressif.com/sites/default/files/documentation/esp32-c6_technical_reference_manual_en.pdf +[s2-trm]: https://www.espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf +[s3-trm]: https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf -The compilation targets for these devices are officially supported by the mainline Rust compiler and can be installed using [rustup](https://rustup.rs/): +## Minimum Supported Rust Version (MSRV) -```shell -rustup target add riscv32imc-unknown-none-elf -rustup target add riscv32imac-unknown-none-elf -``` +This crate is guaranteed to compile on stable Rust 1.76 and up. It _might_ +compile with older versions but that may change in any new patch release. ## License diff --git a/esp-metadata/README.md b/esp-metadata/README.md index c96e0d81e6b..bf169f5bbba 100644 --- a/esp-metadata/README.md +++ b/esp-metadata/README.md @@ -2,10 +2,13 @@ [![Crates.io](https://img.shields.io/crates/v/esp-metadata?color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp-metadata) [![docs.rs](https://img.shields.io/docsrs/esp-metadata?color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp-metadata) -![MSRV](https://img.shields.io/badge/MSRV-1.60-blue?style=flat-square) +![MSRV](https://img.shields.io/badge/MSRV-1.60-blue?labelColor=1C2C2E&style=flat-square) ![Crates.io](https://img.shields.io/crates/l/esp-metadata?style=flat-square) +[![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?label=join%20matrix&labelColor=1C2C2E&color=BEC5C9&logo=matrix&style=flat-square)](https://matrix.to/#/#esp-rs:matrix.org) -Metadata for Espressif devices, primarily intended for use in build scripts. +Metadata for Espressif devices, intended for use in [build scripts]. + +[build scripts]: https://doc.rust-lang.org/cargo/reference/build-scripts.html ## [Documentation](https://docs.rs/crate/esp-metadata) diff --git a/esp-riscv-rt/README.md b/esp-riscv-rt/README.md index 100fc6b364e..ece7af9cb9b 100644 --- a/esp-riscv-rt/README.md +++ b/esp-riscv-rt/README.md @@ -1,27 +1,30 @@ # esp-riscv-rt -[![Crates.io](https://img.shields.io/crates/v/esp-riscv-rt?color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp-riscv-rt) -[![docs.rs](https://img.shields.io/docsrs/esp-riscv-rt?color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp-riscv-rt) -![MSRV](https://img.shields.io/badge/MSRV-1.60-blue?style=flat-square) -![Crates.io](https://img.shields.io/crates/l/esp-riscv-rt?style=flat-square) +[![Crates.io](https://img.shields.io/crates/v/esp-riscv-rt?labelColor=1C2C2E&color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp-riscv-rt) +[![docs.rs](https://img.shields.io/docsrs/esp-riscv-rt?labelColor=1C2C2E&color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp-riscv-rt) +![MSRV](https://img.shields.io/badge/MSRV-1.60-blue?labelColor=1C2C2E&style=flat-square) +![Crates.io](https://img.shields.io/crates/l/esp-riscv-rt?labelColor=1C2C2E&style=flat-square) +[![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?label=join%20matrix&labelColor=1C2C2E&color=BEC5C9&logo=matrix&style=flat-square)](https://matrix.to/#/#esp-rs:matrix.org) -> Minimal runtime / startup for RISC-V CPUs from Espressif. +Minimal runtime / startup for RISC-V devices from Espressif. -Much of the code in this repository originated in the [rust-embedded/riscv-rt](https://github.com/rust-embedded/riscv-rt) repository. +Much of the code in this package originated in the [rust-embedded/riscv] repository. + +[rust-embedded/riscv]: https://github.com/rust-embedded/riscv ## [Documentation](https://docs.rs/crate/esp-riscv-rt) ## Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.60 and up. It _might_ +This crate is guaranteed to compile on stable Rust 1.65 and up. It _might_ compile with older versions but that may change in any new patch release. ## License Licensed under either of: -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) +- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. diff --git a/examples/Cargo.toml b/examples/Cargo.toml index c83f4275bc2..7821dd53127 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -77,13 +77,3 @@ incremental = false opt-level = 3 lto = 'fat' overflow-checks = false - -[patch.crates-io] -esp32 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } -esp32s2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } -esp32s3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } -esp32c2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } -esp32c3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } -esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } -esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } -esp32p4 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280621f0b7ec26546a5eff24a5032305437f" } From ace679f13bfbe089b45d3d677d0eb2191804ddd3 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Mon, 25 Mar 2024 13:14:22 +0000 Subject: [PATCH 14/16] Make examples less dependent on `embedded-hal` where able (#1342) * Add support for building a package without its default features to `xtask` * Do not require `embedded_hal_02` traits in examples where they are not required * Do not require `embedded_hal_02` traits for filling a buffer with random bytes --- esp-hal/src/rng.rs | 41 ++++++++++++++------------- examples/src/bin/crc.rs | 11 ++----- examples/src/bin/ecc.rs | 24 ++++++++-------- examples/src/bin/hello_world.rs | 20 ++++++------- examples/src/bin/hmac.rs | 4 +-- examples/src/bin/i2c_display.rs | 15 +++------- examples/src/bin/multicore.rs | 18 +++--------- examples/src/bin/ram.rs | 12 ++------ examples/src/bin/rng.rs | 4 +-- examples/src/bin/serial_interrupts.rs | 12 +++----- examples/src/bin/usb_serial_jtag.rs | 12 ++------ examples/src/bin/watchdog.rs | 21 +++++++------- xtask/src/lib.rs | 5 ++++ xtask/src/main.rs | 11 ++++++- 14 files changed, 91 insertions(+), 119 deletions(-) diff --git a/esp-hal/src/rng.rs b/esp-hal/src/rng.rs index 8ea996f4a7b..116183b43c8 100644 --- a/esp-hal/src/rng.rs +++ b/esp-hal/src/rng.rs @@ -63,8 +63,6 @@ //! rng.read(&mut buffer).unwrap(); //! ``` -#[cfg(feature = "embedded-hal-02")] -use core::convert::Infallible; use core::marker::PhantomData; use crate::{peripheral::Peripheral, peripherals::RNG}; @@ -95,48 +93,53 @@ impl Rng { .read() .bits() } -} - -#[cfg(feature = "embedded-hal-02")] -impl embedded_hal_02::blocking::rng::Read for Rng { - type Error = Infallible; - fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> { + #[inline] + /// Reads enough bytes from hardware random number generator to fill + /// `buffer`. + /// + /// If any error is encountered then this function immediately returns. The + /// contents of buf are unspecified in this case. + /// + /// If this function returns an error, it is unspecified how many bytes it + /// has read, but it will never read more than would be necessary to + /// completely fill the buffer. + pub fn read(&mut self, buffer: &mut [u8]) { for chunk in buffer.chunks_mut(4) { let bytes = self.random().to_le_bytes(); chunk.copy_from_slice(&bytes[..chunk.len()]); } + } +} + +#[cfg(feature = "embedded-hal-02")] +impl embedded_hal_02::blocking::rng::Read for Rng { + type Error = core::convert::Infallible; + fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> { + self.read(buffer); Ok(()) } } impl rand_core::RngCore for Rng { fn next_u32(&mut self) -> u32 { - // Directly use the existing random method to get a u32 random number self.random() } fn next_u64(&mut self) -> u64 { - // Call random() twice to generate a u64 random number (сombine two u32) let upper = self.random() as u64; let lower = self.random() as u64; + (upper << 32) | lower } fn fill_bytes(&mut self, dest: &mut [u8]) { - // Fill the destination buffer with random bytes - for chunk in dest.chunks_mut(4) { - let rand_bytes = self.random().to_le_bytes(); - for (dest_byte, rand_byte) in chunk.iter_mut().zip(&rand_bytes) { - *dest_byte = *rand_byte; - } - } + self.read(dest); } fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { - // Similar implementation as fill_bytes, but encapsulated in a Result - self.fill_bytes(dest); + self.read(dest); Ok(()) } } diff --git a/examples/src/bin/crc.rs b/examples/src/bin/crc.rs index f9d35211945..4b2d6c0bc46 100644 --- a/examples/src/bin/crc.rs +++ b/examples/src/bin/crc.rs @@ -1,24 +1,21 @@ //! This shows example usage of the CRC functions in ROM //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: embedded-hal-02 #![no_std] #![no_main] use core::fmt::Write; -use embedded_hal_02::timer::CountDown; use esp_backtrace as _; use esp_hal::{ clock::ClockControl, + delay::Delay, peripherals::Peripherals, prelude::*, rom::{crc, md5}, - timer::TimerGroup, uart::Uart, }; -use nb::block; #[entry] fn main() -> ! { @@ -26,9 +23,7 @@ fn main() -> ! { let system = peripherals.SYSTEM.split(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); - let mut timer0 = timg0.timer0; - timer0.start(1u64.secs()); + let delay = Delay::new(&clocks); let mut uart0 = Uart::new(peripherals.UART0, &clocks); @@ -95,6 +90,6 @@ fn main() -> ! { ) .unwrap(); - block!(timer0.wait()).unwrap(); + delay.delay(1.secs()); } } diff --git a/examples/src/bin/ecc.rs b/examples/src/bin/ecc.rs index 58b9627c21b..5e0583e25ea 100644 --- a/examples/src/bin/ecc.rs +++ b/examples/src/bin/ecc.rs @@ -2,7 +2,6 @@ //! hardware-accelerated and pure software ECC. //% CHIPS: esp32c2 esp32c6 esp32h2 -//% FEATURES: embedded-hal-02 #![no_std] #![no_main] @@ -16,10 +15,11 @@ use crypto_bigint::{ U256, }; use elliptic_curve::sec1::ToEncodedPoint; -use embedded_hal_02::blocking::rng::Read; use esp_backtrace as _; +#[cfg(feature = "esp32h2")] +use esp_hal::ecc::WorkMode; use esp_hal::{ - ecc::{Ecc, EllipticCurve, Error, WorkMode}, + ecc::{Ecc, EllipticCurve, Error}, peripherals::Peripherals, prelude::*, rng::Rng, @@ -89,7 +89,7 @@ fn test_affine_point_multiplication(ecc: &mut Ecc, rng: &mut Rng) { let mut delta_time = 0; for _ in 0..TEST_PARAMS_VECTOR.nb_loop_mul { loop { - rng.read(k).unwrap(); + rng.read(k); let is_zero = k.iter().all(|&elt| elt == 0); let is_modulus = k.iter().zip(prime_field).all(|(&a, &b)| a == b); if is_zero == false && is_modulus == false { @@ -202,7 +202,7 @@ fn test_affine_point_verification(ecc: &mut Ecc, rng: &mut Rng) { let mut delta_time = 0; for _ in 0..TEST_PARAMS_VECTOR.nb_loop_mul { loop { - rng.read(k).unwrap(); + rng.read(k); let is_zero = k.iter().all(|&elt| elt == 0); let is_modulus = k.iter().zip(prime_field).all(|(&a, &b)| a == b); if is_zero == false && is_modulus == false { @@ -278,7 +278,7 @@ fn test_afine_point_verification_multiplication(ecc: &mut Ecc, rng: &mut Rng) { let qz = &mut [0u8; 8]; for _ in 0..TEST_PARAMS_VECTOR.nb_loop_mul { loop { - rng.read(k).unwrap(); + rng.read(k); let is_zero = k.iter().all(|&elt| elt == 0); let is_modulus = k.iter().zip(prime_field).all(|(&a, &b)| a == b); if is_zero == false && is_modulus == false { @@ -407,7 +407,7 @@ fn test_jacobian_point_multiplication(ecc: &mut Ecc, rng: &mut Rng) { let (sw_k, _) = sw_k.split_at_mut(prime_field.len()); loop { - rng.read(k).unwrap(); + rng.read(k); let is_zero = k.iter().all(|&elt| elt == 0); let is_modulus = k.iter().zip(prime_field).all(|(&a, &b)| a == b); if is_zero == false && is_modulus == false { @@ -535,8 +535,8 @@ fn test_jacobian_point_verification(ecc: &mut Ecc, rng: &mut Rng) { let mut delta_time = 0; for _ in 0..TEST_PARAMS_VECTOR.nb_loop_mul { loop { - rng.read(k).unwrap(); - rng.read(z).unwrap(); + rng.read(k); + rng.read(z); let is_zero = k.iter().all(|&elt| elt == 0) || z.iter().all(|&elt| elt == 0); let is_modulus = k.iter().zip(prime_field).all(|(&a, &b)| a == b) || z.iter().zip(prime_field).all(|(&a, &b)| a == b); @@ -629,7 +629,7 @@ fn test_afine_point_verification_jacobian_multiplication(ecc: &mut Ecc, rng: &mu let (sw_k, _) = sw_k.split_at_mut(prime_field.len()); loop { - rng.read(k).unwrap(); + rng.read(k); let is_zero = k.iter().all(|&elt| elt == 0); let is_modulus = k.iter().zip(prime_field).all(|(&a, &b)| a == b); if is_zero == false && is_modulus == false { @@ -763,8 +763,8 @@ fn test_finite_field_division(ecc: &mut Ecc, rng: &mut Rng) { let mut delta_time = 0; for _ in 0..TEST_PARAMS_VECTOR.nb_loop_inv { loop { - rng.read(k).unwrap(); - rng.read(y).unwrap(); + rng.read(k); + rng.read(y); let is_zero = k.iter().all(|&elt| elt == 0) || y.iter().all(|&elt| elt == 0); let is_modulus = k.iter().zip(prime_field).all(|(&a, &b)| a == b) || y.iter().zip(prime_field).all(|(&a, &b)| a == b); diff --git a/examples/src/bin/hello_world.rs b/examples/src/bin/hello_world.rs index 0846c260cca..054006ce520 100644 --- a/examples/src/bin/hello_world.rs +++ b/examples/src/bin/hello_world.rs @@ -1,29 +1,27 @@ //! This shows how to write text to UART0. //! //! You can see the output with `espflash` if you provide the `--monitor` -//! option. Depending on the chip, you will need to ensure that you are -//! connected to the UART USB port, and not the USB-SERIAL-JTAG port. -//! If you want to test printing over USB-SERIAL-JTAG, try the usb_serial_jtag -//! example instead. +//! option. +//! +//! Depending on the chip, you will need to ensure that you are connected to +//! the UART USB port, and not the USB-SERIAL-JTAG port. If you want to test +//! printing over USB-SERIAL-JTAG, try the usb_serial_jtag example instead. //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: embedded-hal-02 #![no_std] #![no_main] use core::fmt::Write; -use embedded_hal_02::timer::CountDown; use esp_backtrace as _; use esp_hal::{ clock::ClockControl, + delay::Delay, peripherals::Peripherals, prelude::*, - timer::TimerGroup, uart::Uart, }; -use nb::block; #[entry] fn main() -> ! { @@ -31,14 +29,12 @@ fn main() -> ! { let system = peripherals.SYSTEM.split(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); - let mut timer0 = timg0.timer0; - timer0.start(1u64.secs()); + let delay = Delay::new(&clocks); let mut uart0 = Uart::new(peripherals.UART0, &clocks); loop { writeln!(uart0, "Hello world!").unwrap(); - block!(timer0.wait()).unwrap(); + delay.delay(1.secs()); } } diff --git a/examples/src/bin/hmac.rs b/examples/src/bin/hmac.rs index 0e7c6d8bf35..1297337b9e2 100644 --- a/examples/src/bin/hmac.rs +++ b/examples/src/bin/hmac.rs @@ -53,12 +53,10 @@ //! ``` //% CHIPS: esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: embedded-hal-02 #![no_std] #![no_main] -use embedded_hal_02::blocking::rng::Read; use esp_backtrace as _; use esp_hal::{ clock::ClockControl, @@ -89,7 +87,7 @@ fn main() -> ! { let mut hw_hmac = Hmac::new(peripherals.HMAC); let mut src = [0_u8; 1024]; - rng.read(src.as_mut_slice()).unwrap(); + rng.read(src.as_mut_slice()); // println!("HMAC input {:02X?}", src); let mut output = [0u8; 32]; diff --git a/examples/src/bin/i2c_display.rs b/examples/src/bin/i2c_display.rs index 5b3aa91877e..1a42544bbc4 100644 --- a/examples/src/bin/i2c_display.rs +++ b/examples/src/bin/i2c_display.rs @@ -22,17 +22,15 @@ use embedded_graphics::{ prelude::*, text::{Alignment, Text}, }; -use embedded_hal_02::timer::CountDown; use esp_backtrace as _; use esp_hal::{ clock::ClockControl, + delay::Delay, gpio::IO, i2c::I2C, peripherals::Peripherals, prelude::*, - timer::TimerGroup, }; -use nb::block; use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306}; #[entry] @@ -41,9 +39,7 @@ fn main() -> ! { let system = peripherals.SYSTEM.split(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks); - let mut timer0 = timer_group0.timer0; - + let delay = Delay::new(&clocks); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); // Create a new peripheral object with the described wiring @@ -56,9 +52,6 @@ fn main() -> ! { &clocks, ); - // Start timer (5 second interval) - timer0.start(5u64.secs()); - // Initialize display let interface = I2CDisplayInterface::new(i2c); let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0) @@ -102,7 +95,7 @@ fn main() -> ! { display.clear(BinaryColor::Off).unwrap(); // Wait 5 seconds - block!(timer0.wait()).unwrap(); + delay.delay(5.secs()); // Write single-line centered text "Hello World" to buffer Text::with_alignment( @@ -120,6 +113,6 @@ fn main() -> ! { display.clear(BinaryColor::Off).unwrap(); // Wait 5 seconds - block!(timer0.wait()).unwrap(); + delay.delay(5.secs()); } } diff --git a/examples/src/bin/multicore.rs b/examples/src/bin/multicore.rs index 1334ad9338a..6f40fa61539 100644 --- a/examples/src/bin/multicore.rs +++ b/examples/src/bin/multicore.rs @@ -4,7 +4,6 @@ //! second core. //% CHIPS: esp32 esp32s3 -//% FEATURES: embedded-hal-02 #![no_std] #![no_main] @@ -12,17 +11,15 @@ use core::cell::RefCell; use critical_section::Mutex; -use embedded_hal_02::timer::CountDown; use esp_backtrace as _; use esp_hal::{ clock::ClockControl, cpu_control::{CpuControl, Stack}, + delay::Delay, peripherals::Peripherals, prelude::*, - timer::TimerGroup, }; use esp_println::println; -use nb::block; static mut APP_CORE_STACK: Stack<8192> = Stack::new(); @@ -32,14 +29,7 @@ fn main() -> ! { let system = peripherals.SYSTEM.split(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); - let mut timer0 = timg0.timer0; - - let timg1 = TimerGroup::new(peripherals.TIMG1, &clocks); - let mut timer1 = timg1.timer0; - - timer0.start(1u64.secs()); - timer1.start(500u64.millis()); + let delay = Delay::new(&clocks); let counter = Mutex::new(RefCell::new(0u32)); @@ -48,7 +38,7 @@ fn main() -> ! { .start_app_core(unsafe { &mut APP_CORE_STACK }, || { println!("Hello World - Core 1!"); loop { - block!(timer1.wait()).unwrap(); + delay.delay(500.millis()); critical_section::with(|cs| { let mut val = counter.borrow_ref_mut(cs); *val = val.wrapping_add(1); @@ -58,7 +48,7 @@ fn main() -> ! { .unwrap(); loop { - block!(timer0.wait()).unwrap(); + delay.delay(1.secs()); let count = critical_section::with(|cs| *counter.borrow_ref(cs)); println!("Hello World - Core 0! Counter is {}", count); diff --git a/examples/src/bin/ram.rs b/examples/src/bin/ram.rs index 1307510d48a..0139f34ddb8 100644 --- a/examples/src/bin/ram.rs +++ b/examples/src/bin/ram.rs @@ -12,23 +12,20 @@ //! We can also run code from RTC memory. //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: embedded-hal-02 #![no_std] #![no_main] -use embedded_hal_02::timer::CountDown; use esp_backtrace as _; use esp_hal::{ clock::ClockControl, + delay::Delay, macros::ram, peripherals::Peripherals, prelude::*, rtc_cntl::Rtc, - timer::TimerGroup, }; use esp_println::println; -use nb::block; #[ram(rtc_fast)] static mut SOME_INITED_DATA: [u8; 2] = [0xaa, 0xbb]; @@ -45,16 +42,13 @@ fn main() -> ! { let system = peripherals.SYSTEM.split(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); - let mut timer0 = timg0.timer0; + let delay = Delay::new(&clocks); // The RWDT flash boot protection must be enabled, as it is triggered as part of // the example. let mut rtc = Rtc::new(peripherals.LPWR); rtc.rwdt.enable(); - timer0.start(1u64.secs()); - println!( "IRAM function located at {:p}", function_in_ram as *const () @@ -92,7 +86,7 @@ fn main() -> ! { loop { function_in_ram(); - block!(timer0.wait()).unwrap(); + delay.delay(1.secs()); } } diff --git a/examples/src/bin/rng.rs b/examples/src/bin/rng.rs index 4dbb0f80c64..fc87b7d8fda 100644 --- a/examples/src/bin/rng.rs +++ b/examples/src/bin/rng.rs @@ -1,12 +1,10 @@ //! Demonstrates the use of the hardware Random Number Generator (RNG) //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: embedded-hal-02 #![no_std] #![no_main] -use embedded_hal_02::blocking::rng::Read; use esp_backtrace as _; use esp_hal::{peripherals::Peripherals, prelude::*, rng::Rng}; use esp_println::println; @@ -21,7 +19,7 @@ fn main() -> ! { // Fill a buffer with random bytes: let mut buf = [0u8; 16]; - rng.read(&mut buf).unwrap(); + rng.read(&mut buf); println!("Random bytes: {:?}", buf); loop {} diff --git a/examples/src/bin/serial_interrupts.rs b/examples/src/bin/serial_interrupts.rs index 3ebc3f50b66..d6514560964 100644 --- a/examples/src/bin/serial_interrupts.rs +++ b/examples/src/bin/serial_interrupts.rs @@ -11,18 +11,17 @@ use core::{cell::RefCell, fmt::Write}; use critical_section::Mutex; -use embedded_hal_02::{serial::Read, timer::CountDown}; +use embedded_hal_02::serial::Read; use esp_backtrace as _; use esp_hal::{ clock::ClockControl, + delay::Delay, interrupt::{self, Priority}, peripherals::{Interrupt, Peripherals, UART0}, prelude::*, - timer::TimerGroup, uart::{config::AtCmdConfig, Uart}, Blocking, }; -use nb::block; static SERIAL: Mutex>>> = Mutex::new(RefCell::new(None)); @@ -32,8 +31,7 @@ fn main() -> ! { let system = peripherals.SYSTEM.split(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); - let mut timer0 = timg0.timer0; + let delay = Delay::new(&clocks); let mut uart0 = Uart::new(peripherals.UART0, &clocks); uart0.set_at_cmd(AtCmdConfig::new(None, None, None, b'#', None)); @@ -43,8 +41,6 @@ fn main() -> ! { interrupt::enable(Interrupt::UART0, Priority::Priority2).unwrap(); - timer0.start(1u64.secs()); - critical_section::with(|cs| SERIAL.borrow_ref_mut(cs).replace(uart0)); loop { @@ -54,7 +50,7 @@ fn main() -> ! { writeln!(serial, "Hello World! Send a single `#` character or send at least 30 characters and see the interrupts trigger.").ok(); }); - block!(timer0.wait()).unwrap(); + delay.delay(1.secs()); } } diff --git a/examples/src/bin/usb_serial_jtag.rs b/examples/src/bin/usb_serial_jtag.rs index 28c70431324..b23926fd392 100644 --- a/examples/src/bin/usb_serial_jtag.rs +++ b/examples/src/bin/usb_serial_jtag.rs @@ -4,7 +4,6 @@ //! Most dev-kits use a USB-UART-bridge - in that case you won't see any output. //% CHIPS: esp32c3 esp32c6 esp32h2 esp32s3 -//% FEATURES: embedded-hal-02 #![no_std] #![no_main] @@ -12,17 +11,15 @@ use core::{cell::RefCell, fmt::Write}; use critical_section::Mutex; -use embedded_hal_02::timer::CountDown; use esp_backtrace as _; use esp_hal::{ clock::ClockControl, + delay::Delay, interrupt::{self, Priority}, peripherals::{Interrupt, Peripherals}, prelude::*, - timer::TimerGroup, usb_serial_jtag::UsbSerialJtag, }; -use nb::block; static USB_SERIAL: Mutex>> = Mutex::new(RefCell::new(None)); @@ -32,10 +29,7 @@ fn main() -> ! { let system = peripherals.SYSTEM.split(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); - let mut timer0 = timg0.timer0; - - timer0.start(1.secs()); + let delay = Delay::new(&clocks); let mut usb_serial = UsbSerialJtag::new(peripherals.USB_DEVICE); usb_serial.listen_rx_packet_recv_interrupt(); @@ -52,7 +46,7 @@ fn main() -> ! { .ok(); }); - block!(timer0.wait()).unwrap(); + delay.delay(1.secs()); } } diff --git a/examples/src/bin/watchdog.rs b/examples/src/bin/watchdog.rs index b55bc786233..f13e07c3aa2 100644 --- a/examples/src/bin/watchdog.rs +++ b/examples/src/bin/watchdog.rs @@ -9,14 +9,16 @@ #![no_std] #![no_main] -use embedded_hal_02::{ - timer::CountDown, - watchdog::{Watchdog, WatchdogEnable}, -}; +use embedded_hal_02::watchdog::{Watchdog, WatchdogEnable}; use esp_backtrace as _; -use esp_hal::{clock::ClockControl, peripherals::Peripherals, prelude::*, timer::TimerGroup}; +use esp_hal::{ + clock::ClockControl, + delay::Delay, + peripherals::Peripherals, + prelude::*, + timer::TimerGroup, +}; use esp_println::println; -use nb::block; #[entry] fn main() -> ! { @@ -24,16 +26,15 @@ fn main() -> ! { let system = peripherals.SYSTEM.split(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + let delay = Delay::new(&clocks); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); - let mut timer0 = timg0.timer0; let mut wdt0 = timg0.wdt; - wdt0.start(2u64.secs()); - timer0.start(1u64.secs()); loop { wdt0.feed(); println!("Hello world!"); - block!(timer0.wait()).unwrap(); + delay.delay(1.secs()); } } diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index e47a0cb2540..ba144bfdace 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs @@ -334,6 +334,7 @@ pub fn run_example( pub fn build_package( package_path: &Path, features: Vec, + no_default_features: bool, toolchain: Option, target: Option, ) -> Result<()> { @@ -362,6 +363,10 @@ pub fn build_package( builder = builder.features(&features); } + if no_default_features { + builder = builder.arg("--no-default-features"); + } + let args = builder.build(); log::debug!("{args:#?}"); diff --git a/xtask/src/main.rs b/xtask/src/main.rs index d74c05216d7..597d4f053fb 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -64,6 +64,9 @@ struct BuildPackageArgs { /// Toolchain to build with. #[arg(long)] toolchain: Option, + /// Don't enabled the default features. + #[arg(long)] + no_default_features: bool, } #[derive(Debug, Args)] @@ -233,7 +236,13 @@ fn build_package(workspace: &Path, args: BuildPackageArgs) -> Result<()> { let package_path = xtask::windows_safe_path(&workspace.join(args.package.to_string())); // Build the package using the provided features and/or target, if any: - xtask::build_package(&package_path, args.features, args.toolchain, args.target) + xtask::build_package( + &package_path, + args.features, + args.no_default_features, + args.toolchain, + args.target, + ) } fn bump_version(workspace: &Path, args: BumpVersionArgs) -> Result<()> { From d761ec4def54af7d3ef5f27349fd7787e0512c8a Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Mon, 25 Mar 2024 13:50:18 +0000 Subject: [PATCH 15/16] Address `clippy` lint warnings from latest Xtensa toolchain (#1343) --- esp-hal/src/soc/esp32/mod.rs | 14 +++++++++++--- esp-hal/src/soc/esp32s2/mod.rs | 14 +++++++++++--- esp-hal/src/soc/esp32s3/mod.rs | 14 +++++++++++--- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/esp-hal/src/soc/esp32/mod.rs b/esp-hal/src/soc/esp32/mod.rs index 67936fa8a78..d9e1b59166c 100644 --- a/esp-hal/src/soc/esp32/mod.rs +++ b/esp-hal/src/soc/esp32/mod.rs @@ -5,6 +5,8 @@ //! The `SOC` module provides access, functions and structures that are useful //! for interacting with various system-related peripherals on `ESP32` chip. +use core::ptr::addr_of_mut; + use self::peripherals::{LPWR, TIMG0, TIMG1}; use crate::{rtc_cntl::Rtc, timer::Wdt}; @@ -52,14 +54,20 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { } // set stack pointer to end of memory: no need to retain stack up to this point - xtensa_lx::set_stack_pointer(&mut _stack_start_cpu0); + xtensa_lx::set_stack_pointer(addr_of_mut!(_stack_start_cpu0)); // copying data from flash to various data segments is done by the bootloader // initialization to zero needs to be done by the application // Initialize RTC RAM - xtensa_lx_rt::zero_bss(&mut _rtc_fast_bss_start, &mut _rtc_fast_bss_end); - xtensa_lx_rt::zero_bss(&mut _rtc_slow_bss_start, &mut _rtc_slow_bss_end); + xtensa_lx_rt::zero_bss( + addr_of_mut!(_rtc_fast_bss_start), + addr_of_mut!(_rtc_fast_bss_end), + ); + xtensa_lx_rt::zero_bss( + addr_of_mut!(_rtc_slow_bss_start), + addr_of_mut!(_rtc_slow_bss_end), + ); unsafe { let stack_chk_guard = core::ptr::addr_of_mut!(__stack_chk_guard); diff --git a/esp-hal/src/soc/esp32s2/mod.rs b/esp-hal/src/soc/esp32s2/mod.rs index 7df5afc5215..a54650347d3 100644 --- a/esp-hal/src/soc/esp32s2/mod.rs +++ b/esp-hal/src/soc/esp32s2/mod.rs @@ -9,6 +9,8 @@ //! * I2S_SCLK: 160_000_000 - I2S clock frequency //! * I2S_DEFAULT_CLK_SRC: 2 - I2S clock source +use core::ptr::addr_of_mut; + use self::peripherals::{LPWR, TIMG0, TIMG1}; use crate::{rtc_cntl::Rtc, timer::Wdt}; @@ -56,14 +58,20 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { } // set stack pointer to end of memory: no need to retain stack up to this point - xtensa_lx::set_stack_pointer(&mut _stack_start_cpu0); + xtensa_lx::set_stack_pointer(addr_of_mut!(_stack_start_cpu0)); // copying data from flash to various data segments is done by the bootloader // initialization to zero needs to be done by the application // Initialize RTC RAM - xtensa_lx_rt::zero_bss(&mut _rtc_fast_bss_start, &mut _rtc_fast_bss_end); - xtensa_lx_rt::zero_bss(&mut _rtc_slow_bss_start, &mut _rtc_slow_bss_end); + xtensa_lx_rt::zero_bss( + addr_of_mut!(_rtc_fast_bss_start), + addr_of_mut!(_rtc_fast_bss_end), + ); + xtensa_lx_rt::zero_bss( + addr_of_mut!(_rtc_slow_bss_start), + addr_of_mut!(_rtc_slow_bss_end), + ); unsafe { let stack_chk_guard = core::ptr::addr_of_mut!(__stack_chk_guard); diff --git a/esp-hal/src/soc/esp32s3/mod.rs b/esp-hal/src/soc/esp32s3/mod.rs index 69f7034a517..5dc5918fca0 100644 --- a/esp-hal/src/soc/esp32s3/mod.rs +++ b/esp-hal/src/soc/esp32s3/mod.rs @@ -9,6 +9,8 @@ //! * I2S_SCLK: 160_000_000 - I2S clock frequency //! * I2S_DEFAULT_CLK_SRC: 2 - I2S clock source +use core::ptr::addr_of_mut; + use self::peripherals::{LPWR, TIMG0, TIMG1}; use crate::{rtc_cntl::Rtc, timer::Wdt}; @@ -91,14 +93,20 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { } // set stack pointer to end of memory: no need to retain stack up to this point - xtensa_lx::set_stack_pointer(&mut _stack_start_cpu0); + xtensa_lx::set_stack_pointer(addr_of_mut!(_stack_start_cpu0)); // copying data from flash to various data segments is done by the bootloader // initialization to zero needs to be done by the application // Initialize RTC RAM - xtensa_lx_rt::zero_bss(&mut _rtc_fast_bss_start, &mut _rtc_fast_bss_end); - xtensa_lx_rt::zero_bss(&mut _rtc_slow_bss_start, &mut _rtc_slow_bss_end); + xtensa_lx_rt::zero_bss( + addr_of_mut!(_rtc_fast_bss_start), + addr_of_mut!(_rtc_fast_bss_end), + ); + xtensa_lx_rt::zero_bss( + addr_of_mut!(_rtc_slow_bss_start), + addr_of_mut!(_rtc_slow_bss_end), + ); unsafe { let stack_chk_guard = core::ptr::addr_of_mut!(__stack_chk_guard); From fd4f5592a4776afdce9565d0210ba6dedcf51eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Mon, 25 Mar 2024 14:54:03 +0100 Subject: [PATCH 16/16] RMT: allow driver to init as blocking or async (#1341) * RMT: allow driver to init as blocking or async * CHANGELOG and minor fixes --- esp-hal-procmacros/src/lib.rs | 56 ++- esp-hal/CHANGELOG.md | 1 + esp-hal/src/embassy/mod.rs | 3 - esp-hal/src/interrupt/xtensa.rs | 15 + esp-hal/src/lib.rs | 2 + esp-hal/src/rmt.rs | 587 +++++++++++++++++++++-------- esp-hal/src/soc/esp32/mod.rs | 2 + esp-hal/src/soc/esp32s2/mod.rs | 2 + esp-hal/src/soc/esp32s3/mod.rs | 2 + examples/src/bin/embassy_rmt_rx.rs | 4 +- examples/src/bin/embassy_rmt_tx.rs | 4 +- examples/src/bin/hello_rgb.rs | 4 +- examples/src/bin/rmt_rx.rs | 2 +- examples/src/bin/rmt_tx.rs | 2 +- 14 files changed, 500 insertions(+), 186 deletions(-) diff --git a/esp-hal-procmacros/src/lib.rs b/esp-hal-procmacros/src/lib.rs index 1f285faa870..fb5f094f5d9 100644 --- a/esp-hal-procmacros/src/lib.rs +++ b/esp-hal-procmacros/src/lib.rs @@ -361,9 +361,12 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { /// Mark a function as an interrupt handler. /// -/// This is really just a nicer looking way to make a function `unsafe extern -/// "C"` +/// Optionally a priority can be specified, e.g. `#[handler("Priority3")]`, +/// "min" and "max" are special values. +/// +/// If no priority is given, "Priority::min()" is assumed #[cfg(feature = "interrupt")] +#[proc_macro_error::proc_macro_error] #[proc_macro_attribute] pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { use darling::ast::NestedMeta; @@ -385,9 +388,40 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { } }; - if attr_args.len() > 0 { - abort!(Span::call_site(), "This attribute accepts no arguments") - } + let root = Ident::new( + if let Ok(FoundCrate::Name(ref name)) = crate_name("esp-hal") { + &name + } else { + "crate" + }, + Span::call_site().into(), + ); + + let priority = if attr_args.len() > 1 { + abort!( + Span::call_site(), + "This attribute accepts one optional argument" + ) + } else if attr_args.len() == 1 { + match &attr_args[0] { + NestedMeta::Lit(syn::Lit::Str(priority)) => priority.value(), + _ => abort!( + Span::call_site(), + "The priority must be provided as a string" + ), + } + } else { + String::from("min") + }; + + let priority = match priority.as_str() { + "min" => quote::quote_spanned!(original_span => #root::interrupt::Priority::min()), + "max" => quote::quote_spanned!(original_span => #root::interrupt::Priority::max()), + _ => { + let priority = Ident::new(&priority, proc_macro2::Span::call_site()); + quote::quote_spanned!(original_span => #root::interrupt::Priority::#priority) + } + }; // XXX should we blacklist other attributes? @@ -419,17 +453,9 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { .into(); } - let root = Ident::new( - if let Ok(FoundCrate::Name(ref name)) = crate_name("esp-hal") { - &name - } else { - "crate" - }, - Span::call_site().into(), - ); - f.sig.abi = syn::parse_quote_spanned!(original_span => extern "C"); let orig = f.sig.ident; + let vis = f.vis.clone(); f.sig.ident = Ident::new( &format!("__esp_hal_internal_{}", orig), proc_macro2::Span::call_site(), @@ -440,7 +466,7 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { #f #[allow(non_upper_case_globals)] - static #orig: #root::interrupt::InterruptHandler = #root::interrupt::InterruptHandler::new(#new, #root::interrupt::Priority::min()); + #vis static #orig: #root::interrupt::InterruptHandler = #root::interrupt::InterruptHandler::new(#new, #priority); ) .into() } diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 3c4add5db50..d039ad349f6 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Renamed `eh1` feature to `embedded-hal`, feature-gated `embedded-hal@0.2.x` trait implementations (#1273) - Enable `embedded-hal` feature by default, instead of the `embedded-hal-02` feature (#1313) - `Uart` structs now take a `Mode` parameter which defines how the driver is initialized (#1294) +- `Rmt` can be created in async or blocking mode. The blocking constructor takes an optional interrupt handler argument. (#1341) ### Removed diff --git a/esp-hal/src/embassy/mod.rs b/esp-hal/src/embassy/mod.rs index cba292ba767..ef3b907f06b 100644 --- a/esp-hal/src/embassy/mod.rs +++ b/esp-hal/src/embassy/mod.rs @@ -150,9 +150,6 @@ pub fn init(clocks: &Clocks, td: time_driver::TimerType) { #[cfg(i2s1)] crate::interrupt::enable(Interrupt::I2S1, Priority::min()).unwrap(); - #[cfg(rmt)] - crate::interrupt::enable(Interrupt::RMT, Priority::min()).unwrap(); - #[cfg(usb_device)] crate::interrupt::enable(Interrupt::USB_DEVICE, Priority::min()).unwrap(); diff --git a/esp-hal/src/interrupt/xtensa.rs b/esp-hal/src/interrupt/xtensa.rs index 7545a951a8c..d8b37231ac7 100644 --- a/esp-hal/src/interrupt/xtensa.rs +++ b/esp-hal/src/interrupt/xtensa.rs @@ -68,6 +68,21 @@ pub const RESERVED_INTERRUPTS: &[usize] = &[ CpuInterrupt::Interrupt22EdgePriority3 as _, ]; +pub(crate) fn setup_interrupts() { + // disable all known interrupts + // at least after the 2nd stage bootloader there are some interrupts enabled + // (e.g. UART) + for peripheral_interrupt in 0..255 { + crate::soc::peripherals::Interrupt::try_from(peripheral_interrupt) + .map(|intr| { + #[cfg(multi_core)] + disable(Cpu::AppCpu, intr); + disable(Cpu::ProCpu, intr); + }) + .ok(); + } +} + /// Enable an interrupt by directly binding it to a available CPU interrupt /// /// Unless you are sure, you most likely want to use [`enable`] with the diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index fd4b4f5b838..78665da2eda 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -158,9 +158,11 @@ extern "C" fn EspDefaultHandler(_interrupt: peripherals::Interrupt) { pub trait Mode: crate::private::Sealed {} /// Driver initialized in blocking mode. +#[derive(Debug)] pub struct Blocking; /// Driver initialized in async mode. +#[derive(Debug)] pub struct Async; impl crate::Mode for Blocking {} diff --git a/esp-hal/src/rmt.rs b/esp-hal/src/rmt.rs index 52820fd2f8d..543d03b6469 100644 --- a/esp-hal/src/rmt.rs +++ b/esp-hal/src/rmt.rs @@ -83,11 +83,14 @@ //! channel = transaction.wait().unwrap(); //! ``` +use core::marker::PhantomData; + use fugit::HertzU32; use crate::{ clock::Clocks, gpio::{InputPin, OutputPin}, + interrupt::InterruptHandler, peripheral::Peripheral, rmt::private::CreateInstance, soc::constants, @@ -201,12 +204,18 @@ pub struct RxChannelConfig { pub use impl_for_chip::Rmt; -impl<'d> Rmt<'d> { - /// Create a new RMT instance - pub fn new( +#[cfg(feature = "async")] +use self::asynch::{RxChannelAsync, TxChannelAsync}; + +impl<'d, M> Rmt<'d, M> +where + M: crate::Mode, +{ + pub fn new_internal( peripheral: impl Peripheral

+ 'd, frequency: HertzU32, _clocks: &Clocks, + interrupt: Option, ) -> Result { let me = Rmt::create(peripheral); @@ -223,6 +232,17 @@ impl<'d> Rmt<'d> { #[cfg(any(esp32, esp32s2))] self::chip_specific::configure_clock(); + if let Some(interrupt) = interrupt { + unsafe { + crate::interrupt::bind_interrupt( + crate::peripherals::Interrupt::RMT, + interrupt.handler(), + ); + crate::interrupt::enable(crate::peripherals::Interrupt::RMT, interrupt.priority()) + .unwrap(); + } + } + Ok(me) } @@ -246,6 +266,35 @@ impl<'d> Rmt<'d> { } } +impl<'d> Rmt<'d, crate::Blocking> { + /// Create a new RMT instance + pub fn new( + peripheral: impl Peripheral

+ 'd, + frequency: HertzU32, + _clocks: &Clocks, + interrupt: Option, + ) -> Result { + Self::new_internal(peripheral, frequency, _clocks, interrupt) + } +} + +#[cfg(feature = "async")] +impl<'d> Rmt<'d, crate::Async> { + /// Create a new RMT instance + pub fn new_async( + peripheral: impl Peripheral

+ 'd, + frequency: HertzU32, + _clocks: &Clocks, + ) -> Result { + Self::new_internal( + peripheral, + frequency, + _clocks, + Some(asynch::async_interrupt_handler), + ) + } +} + pub trait TxChannelCreator<'d, T, P> where P: OutputPin, @@ -276,6 +325,37 @@ where } } +#[cfg(feature = "async")] +pub trait TxChannelCreatorAsync<'d, T, P> +where + P: OutputPin, + T: TxChannelAsync, +{ + /// Configure the TX channel + fn configure( + self, + pin: impl Peripheral

+ 'd, + config: TxChannelConfig, + ) -> Result + where + Self: Sized, + { + crate::into_ref!(pin); + pin.set_to_push_pull_output() + .connect_peripheral_to_output(T::output_signal()); + T::set_divider(config.clk_divider); + T::set_carrier( + config.carrier_modulation, + config.carrier_high, + config.carrier_low, + config.carrier_level, + ); + T::set_idle_output(config.idle_output, config.idle_output_level); + + Ok(T::new()) + } +} + pub trait RxChannelCreator<'d, T, P> where P: InputPin, @@ -321,6 +401,52 @@ where } } +#[cfg(feature = "async")] +pub trait RxChannelCreatorAsync<'d, T, P> +where + P: InputPin, + T: RxChannelAsync, +{ + /// Configure the RX channel + fn configure( + self, + pin: impl Peripheral

+ 'd, + config: RxChannelConfig, + ) -> Result + where + Self: Sized, + { + if config.filter_threshold > 0b111_1111 { + return Err(Error::InvalidArgument); + } + + #[cfg(any(esp32, esp32s2))] + if config.idle_threshold > 0b111_1111_1111_1111 { + return Err(Error::InvalidArgument); + } + + #[cfg(not(any(esp32, esp32s2)))] + if config.idle_threshold > 0b11_1111_1111_1111 { + return Err(Error::InvalidArgument); + } + + crate::into_ref!(pin); + pin.set_to_input() + .connect_input_to_peripheral(T::input_signal()); + T::set_divider(config.clk_divider); + T::set_carrier( + config.carrier_modulation, + config.carrier_high, + config.carrier_low, + config.carrier_level, + ); + T::set_filter_threshold(config.filter_threshold); + T::set_idle_threshold(config.idle_threshold); + + Ok(T::new()) + } +} + /// An in-progress transaction for a single shot TX transaction. pub struct SingleShotTxTransaction<'a, C, T: Into + Copy> where @@ -338,18 +464,18 @@ where /// Wait for the transaction to complete pub fn wait(mut self) -> Result { loop { - if ::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } if self.index < self.data.len() { // wait for TX-THR loop { - if ::is_threshold_set() { + if >::is_threshold_set() { break; } } - ::reset_threshold_set(); + >::reset_threshold_set(); // re-fill TX RAM let ram_index = (((self.index - constants::RMT_CHANNEL_RAM_SIZE) @@ -377,11 +503,11 @@ where } loop { - if ::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if ::is_done() { + if >::is_done() { break; } } @@ -404,15 +530,15 @@ where { /// Stop transaction when the current iteration ends. pub fn stop_next(self) -> Result { - ::set_continuous(false); - ::update(); + >::set_continuous(false); + >::update(); loop { - if ::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if ::is_done() { + if >::is_done() { break; } } @@ -422,8 +548,8 @@ where /// Stop transaction as soon as possible. pub fn stop(self) -> Result { - ::set_continuous(false); - ::update(); + >::set_continuous(false); + >::update(); let ptr = (constants::RMT_RAM_START + C::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) @@ -435,11 +561,11 @@ where } loop { - if ::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if ::is_done() { + if >::is_done() { break; } } @@ -448,71 +574,110 @@ where } pub fn is_loopcount_interrupt_set(&self) -> bool { - ::is_loopcount_interrupt_set() + >::is_loopcount_interrupt_set() } } macro_rules! impl_tx_channel_creator { ($channel:literal) => { - impl<'d, P> $crate::rmt::TxChannelCreator<'d, $crate::rmt::Channel<$channel>, P> - for ChannelCreator<$channel> + impl<'d, P> $crate::rmt::TxChannelCreator<'d, $crate::rmt::Channel<$crate::Blocking, $channel>, P> + for ChannelCreator<$crate::Blocking, $channel> where P: $crate::gpio::OutputPin, { } - impl $crate::rmt::TxChannel for $crate::rmt::Channel<$channel> {} + impl $crate::rmt::TxChannel for $crate::rmt::Channel<$crate::Blocking, $channel> {} + + #[cfg(feature = "async")] + impl<'d, P> $crate::rmt::TxChannelCreatorAsync<'d, $crate::rmt::Channel<$crate::Async, $channel>, P> + for ChannelCreator<$crate::Async, $channel> + where + P: $crate::gpio::OutputPin, + { + } #[cfg(feature = "async")] - impl $crate::rmt::asynch::TxChannelAsync for $crate::rmt::Channel<$channel> {} + impl $crate::rmt::asynch::TxChannelAsync for $crate::rmt::Channel<$crate::Async, $channel> {} }; } macro_rules! impl_rx_channel_creator { ($channel:literal) => { - impl<'d, P> $crate::rmt::RxChannelCreator<'d, $crate::rmt::Channel<$channel>, P> - for ChannelCreator<$channel> + impl<'d, P> $crate::rmt::RxChannelCreator<'d, $crate::rmt::Channel<$crate::Blocking, $channel>, P> + for ChannelCreator<$crate::Blocking, $channel> where P: $crate::gpio::InputPin, { } - impl $crate::rmt::RxChannel for $crate::rmt::Channel<$channel> {} + impl $crate::rmt::RxChannel for $crate::rmt::Channel<$crate::Blocking, $channel> {} #[cfg(feature = "async")] - impl $crate::rmt::asynch::RxChannelAsync for $crate::rmt::Channel<$channel> {} + impl<'d, P> $crate::rmt::RxChannelCreatorAsync<'d, $crate::rmt::Channel<$crate::Async, $channel>, P> + for ChannelCreator<$crate::Async, $channel> + where + P: $crate::gpio::InputPin, + { + } + + #[cfg(feature = "async")] + impl $crate::rmt::asynch::RxChannelAsync for $crate::rmt::Channel<$crate::Async, $channel> {} }; } #[cfg(not(any(esp32, esp32s2, esp32s3)))] mod impl_for_chip { + use core::marker::PhantomData; + use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance - pub struct Rmt<'d> { + pub struct Rmt<'d, M> + where + M: crate::Mode, + { _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, - pub channel0: ChannelCreator<0>, - pub channel1: ChannelCreator<1>, - pub channel2: ChannelCreator<2>, - pub channel3: ChannelCreator<3>, + pub channel0: ChannelCreator, + pub channel1: ChannelCreator, + pub channel2: ChannelCreator, + pub channel3: ChannelCreator, + phantom: PhantomData, } - impl<'d> CreateInstance<'d> for Rmt<'d> { + impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + where + M: crate::Mode, + { fn create(peripheral: impl Peripheral

+ 'd) -> Self { crate::into_ref!(peripheral); Self { _peripheral: peripheral, - channel0: ChannelCreator {}, - channel1: ChannelCreator {}, - channel2: ChannelCreator {}, - channel3: ChannelCreator {}, + channel0: ChannelCreator { + phantom: PhantomData, + }, + channel1: ChannelCreator { + phantom: PhantomData, + }, + channel2: ChannelCreator { + phantom: PhantomData, + }, + channel3: ChannelCreator { + phantom: PhantomData, + }, + phantom: PhantomData, } } } - pub struct ChannelCreator {} + pub struct ChannelCreator + where + M: crate::Mode, + { + phantom: PhantomData, + } impl_tx_channel_creator!(0); impl_tx_channel_creator!(1); @@ -529,41 +694,72 @@ mod impl_for_chip { #[cfg(esp32)] mod impl_for_chip { + use core::marker::PhantomData; + use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance - pub struct Rmt<'d> { + pub struct Rmt<'d, M> + where + M: crate::Mode, + { _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, - pub channel0: ChannelCreator<0>, - pub channel1: ChannelCreator<1>, - pub channel2: ChannelCreator<2>, - pub channel3: ChannelCreator<3>, - pub channel4: ChannelCreator<4>, - pub channel5: ChannelCreator<5>, - pub channel6: ChannelCreator<6>, - pub channel7: ChannelCreator<7>, + pub channel0: ChannelCreator, + pub channel1: ChannelCreator, + pub channel2: ChannelCreator, + pub channel3: ChannelCreator, + pub channel4: ChannelCreator, + pub channel5: ChannelCreator, + pub channel6: ChannelCreator, + pub channel7: ChannelCreator, + phantom: PhantomData, } - impl<'d> CreateInstance<'d> for Rmt<'d> { + impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + where + M: crate::Mode, + { fn create(peripheral: impl Peripheral

+ 'd) -> Self { crate::into_ref!(peripheral); Self { _peripheral: peripheral, - channel0: ChannelCreator {}, - channel1: ChannelCreator {}, - channel2: ChannelCreator {}, - channel3: ChannelCreator {}, - channel4: ChannelCreator {}, - channel5: ChannelCreator {}, - channel6: ChannelCreator {}, - channel7: ChannelCreator {}, + channel0: ChannelCreator { + phantom: PhantomData, + }, + channel1: ChannelCreator { + phantom: PhantomData, + }, + channel2: ChannelCreator { + phantom: PhantomData, + }, + channel3: ChannelCreator { + phantom: PhantomData, + }, + channel4: ChannelCreator { + phantom: PhantomData, + }, + channel5: ChannelCreator { + phantom: PhantomData, + }, + channel6: ChannelCreator { + phantom: PhantomData, + }, + channel7: ChannelCreator { + phantom: PhantomData, + }, + phantom: PhantomData, } } } - pub struct ChannelCreator {} + pub struct ChannelCreator + where + M: crate::Mode, + { + phantom: PhantomData, + } impl_tx_channel_creator!(0); impl_tx_channel_creator!(1); @@ -604,33 +800,56 @@ mod impl_for_chip { #[cfg(esp32s2)] mod impl_for_chip { + use core::marker::PhantomData; + use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance - pub struct Rmt<'d> { + pub struct Rmt<'d, M> + where + M: crate::Mode, + { _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, - pub channel0: ChannelCreator<0>, - pub channel1: ChannelCreator<1>, - pub channel2: ChannelCreator<2>, - pub channel3: ChannelCreator<3>, + pub channel0: ChannelCreator, + pub channel1: ChannelCreator, + pub channel2: ChannelCreator, + pub channel3: ChannelCreator, + phantom: PhantomData, } - impl<'d> CreateInstance<'d> for Rmt<'d> { + impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + where + M: crate::Mode, + { fn create(peripheral: impl Peripheral

+ 'd) -> Self { crate::into_ref!(peripheral); Self { _peripheral: peripheral, - channel0: ChannelCreator {}, - channel1: ChannelCreator {}, - channel2: ChannelCreator {}, - channel3: ChannelCreator {}, + channel0: ChannelCreator { + phantom: PhantomData, + }, + channel1: ChannelCreator { + phantom: PhantomData, + }, + channel2: ChannelCreator { + phantom: PhantomData, + }, + channel3: ChannelCreator { + phantom: PhantomData, + }, + phantom: PhantomData, } } } - pub struct ChannelCreator {} + pub struct ChannelCreator + where + M: crate::Mode, + { + phantom: PhantomData, + } impl_tx_channel_creator!(0); impl_tx_channel_creator!(1); @@ -655,41 +874,72 @@ mod impl_for_chip { #[cfg(esp32s3)] mod impl_for_chip { + use core::marker::PhantomData; + use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance - pub struct Rmt<'d> { + pub struct Rmt<'d, M> + where + M: crate::Mode, + { _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, - pub channel0: ChannelCreator<0>, - pub channel1: ChannelCreator<1>, - pub channel2: ChannelCreator<2>, - pub channel3: ChannelCreator<3>, - pub channel4: ChannelCreator<4>, - pub channel5: ChannelCreator<5>, - pub channel6: ChannelCreator<6>, - pub channel7: ChannelCreator<7>, + pub channel0: ChannelCreator, + pub channel1: ChannelCreator, + pub channel2: ChannelCreator, + pub channel3: ChannelCreator, + pub channel4: ChannelCreator, + pub channel5: ChannelCreator, + pub channel6: ChannelCreator, + pub channel7: ChannelCreator, + phantom: PhantomData, } - impl<'d> CreateInstance<'d> for Rmt<'d> { + impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + where + M: crate::Mode, + { fn create(peripheral: impl Peripheral

+ 'd) -> Self { crate::into_ref!(peripheral); Self { _peripheral: peripheral, - channel0: ChannelCreator {}, - channel1: ChannelCreator {}, - channel2: ChannelCreator {}, - channel3: ChannelCreator {}, - channel4: ChannelCreator {}, - channel5: ChannelCreator {}, - channel6: ChannelCreator {}, - channel7: ChannelCreator {}, + channel0: ChannelCreator { + phantom: PhantomData, + }, + channel1: ChannelCreator { + phantom: PhantomData, + }, + channel2: ChannelCreator { + phantom: PhantomData, + }, + channel3: ChannelCreator { + phantom: PhantomData, + }, + channel4: ChannelCreator { + phantom: PhantomData, + }, + channel5: ChannelCreator { + phantom: PhantomData, + }, + channel6: ChannelCreator { + phantom: PhantomData, + }, + channel7: ChannelCreator { + phantom: PhantomData, + }, + phantom: PhantomData, } } } - pub struct ChannelCreator {} + pub struct ChannelCreator + where + M: crate::Mode, + { + phantom: PhantomData, + } impl_tx_channel_creator!(0); impl_tx_channel_creator!(1); @@ -715,9 +965,14 @@ mod impl_for_chip { /// RMT Channel #[non_exhaustive] #[derive(Debug)] -pub struct Channel {} +pub struct Channel +where + M: crate::Mode, +{ + phantom: PhantomData, +} -pub trait TxChannel: private::TxChannelInternal { +pub trait TxChannel: private::TxChannelInternal { /// Start transmitting the given pulse code sequence. /// This returns a [`SingleShotTxTransaction`] which can be used to wait for /// the transaction to complete and get back the channel for further @@ -784,18 +1039,18 @@ where /// Wait for the transaction to complete pub fn wait(self) -> Result { loop { - if ::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if ::is_done() { + if >::is_done() { break; } } - ::stop(); - ::clear_interrupts(); - ::update(); + >::stop(); + >::clear_interrupts(); + >::update(); let ptr = (constants::RMT_RAM_START + C::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) @@ -809,7 +1064,7 @@ where } } -pub trait RxChannel: private::RxChannelInternal { +pub trait RxChannel: private::RxChannelInternal { /// Start receiving pulse codes into the given buffer. /// This returns a [RxTransaction] which can be used to wait for receive to /// complete and get back the channel for further use. @@ -834,13 +1089,12 @@ pub trait RxChannel: private::RxChannelInternal { #[cfg(feature = "async")] pub mod asynch { use core::{ - marker::PhantomData, pin::Pin, task::{Context, Poll}, }; use embassy_sync::waitqueue::AtomicWaker; - use procmacros::interrupt; + use procmacros::handler; use super::{private::Event, *}; @@ -887,7 +1141,7 @@ pub mod asynch { } } - pub trait TxChannelAsync: private::TxChannelInternal { + pub trait TxChannelAsync: private::TxChannelInternal { /// Start transmitting the given pulse code sequence. /// The length of sequence cannot exceed the size of the allocated RMT /// RAM. @@ -948,7 +1202,7 @@ pub mod asynch { } } - pub trait RxChannelAsync: private::RxChannelInternal { + pub trait RxChannelAsync: private::RxChannelInternal { /// Start receiving a pulse code sequence. /// The length of sequence cannot exceed the size of the allocated RMT /// RAM. @@ -988,49 +1242,48 @@ pub mod asynch { } #[cfg(not(any(esp32, esp32s2)))] - #[interrupt] - fn RMT() { + #[handler] + pub(super) fn async_interrupt_handler() { if let Some(channel) = super::chip_specific::pending_interrupt_for_channel() { use crate::rmt::private::{RxChannelInternal, TxChannelInternal}; match channel { 0 => { - super::Channel::<0>::unlisten_interrupt(Event::End); - super::Channel::<0>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } 1 => { - super::Channel::<1>::unlisten_interrupt(Event::End); - super::Channel::<1>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } 2 => { - super::Channel::<2>::unlisten_interrupt(Event::End); - super::Channel::<2>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } 3 => { - super::Channel::<3>::unlisten_interrupt(Event::End); - super::Channel::<3>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } - // TODO ... how to handle chips which can use a channel for tx AND rx? #[cfg(any(esp32, esp32s3))] 4 => { - super::Channel::<4>::unlisten_interrupt(Event::End); - super::Channel::<4>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } #[cfg(any(esp32, esp32s3))] 5 => { - super::Channel::<5>::unlisten_interrupt(Event::End); - super::Channel::<5>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } #[cfg(any(esp32, esp32s3))] 6 => { - super::Channel::<6>::unlisten_interrupt(Event::End); - super::Channel::<6>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } #[cfg(any(esp32, esp32s3))] 7 => { - super::Channel::<7>::unlisten_interrupt(Event::End); - super::Channel::<7>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } _ => unreachable!(), @@ -1041,123 +1294,123 @@ pub mod asynch { } #[cfg(any(esp32, esp32s2))] - #[interrupt] - fn RMT() { + #[handler] + pub(super) fn async_interrupt_handler() { if let Some(channel) = super::chip_specific::pending_interrupt_for_channel() { match channel { 0 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } 1 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } 2 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } 3 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } #[cfg(esp32)] 4 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } #[cfg(any(esp32, esp32s3))] 5 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } #[cfg(any(esp32, esp32s3))] 6 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } #[cfg(any(esp32, esp32s3))] 7 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } @@ -1183,7 +1436,10 @@ mod private { fn create(peripheral: impl Peripheral

+ 'd) -> Self; } - pub trait TxChannelInternal { + pub trait TxChannelInternal + where + M: crate::Mode, + { const CHANNEL: u8; fn new() -> Self; @@ -1261,7 +1517,10 @@ mod private { fn unlisten_interrupt(event: Event); } - pub trait RxChannelInternal { + pub trait RxChannelInternal + where + M: crate::Mode, + { const CHANNEL: u8; fn new() -> Self; @@ -1396,11 +1655,13 @@ mod chip_specific { macro_rules! impl_tx_channel { ($channel:ident, $signal:ident, $ch_num:literal) => { paste::paste! { - impl $crate::rmt::private::TxChannelInternal for $crate::rmt::$channel<$ch_num> { + impl $crate::rmt::private::TxChannelInternal for $crate::rmt::$channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { - Self {} + Self { + phantom: core::marker::PhantomData, + } } fn output_signal() -> crate::gpio::OutputSignal { @@ -1587,11 +1848,13 @@ mod chip_specific { macro_rules! impl_rx_channel { ($channel:ident, $signal:ident, $ch_num:literal, $ch_index:literal) => { paste::paste! { - impl $crate::rmt::private::RxChannelInternal for $crate::rmt::$channel<$ch_num> { + impl $crate::rmt::private::RxChannelInternal for $crate::rmt::$channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { - Self {} + Self { + phantom: core::marker::PhantomData, + } } fn input_signal() -> crate::gpio::InputSignal { @@ -1801,11 +2064,13 @@ mod chip_specific { macro_rules! impl_tx_channel { ($channel:ident, $signal:ident, $ch_num:literal) => { paste::paste! { - impl super::private::TxChannelInternal for super::$channel<$ch_num> { + impl super::private::TxChannelInternal for super::$channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { - Self {} + Self { + phantom: core::marker::PhantomData, + } } fn output_signal() -> crate::gpio::OutputSignal { @@ -1972,11 +2237,13 @@ mod chip_specific { macro_rules! impl_rx_channel { ($channel:ident, $signal:ident, $ch_num:literal) => { paste::paste! { - impl super::private::RxChannelInternal for super::$channel<$ch_num> { + impl super::private::RxChannelInternal for super::$channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { - Self {} + Self { + phantom: core::marker::PhantomData, + } } fn input_signal() -> crate::gpio::InputSignal { diff --git a/esp-hal/src/soc/esp32/mod.rs b/esp-hal/src/soc/esp32/mod.rs index d9e1b59166c..e065a5a6d01 100644 --- a/esp-hal/src/soc/esp32/mod.rs +++ b/esp-hal/src/soc/esp32/mod.rs @@ -76,6 +76,8 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { stack_chk_guard.write_volatile(0xdeadbabe); } + crate::interrupt::setup_interrupts(); + // continue with default reset handler xtensa_lx_rt::Reset(); } diff --git a/esp-hal/src/soc/esp32s2/mod.rs b/esp-hal/src/soc/esp32s2/mod.rs index a54650347d3..94649c2d9e3 100644 --- a/esp-hal/src/soc/esp32s2/mod.rs +++ b/esp-hal/src/soc/esp32s2/mod.rs @@ -80,6 +80,8 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { stack_chk_guard.write_volatile(0xdeadbabe); } + crate::interrupt::setup_interrupts(); + // continue with default reset handler xtensa_lx_rt::Reset(); } diff --git a/esp-hal/src/soc/esp32s3/mod.rs b/esp-hal/src/soc/esp32s3/mod.rs index 5dc5918fca0..b2bef618e56 100644 --- a/esp-hal/src/soc/esp32s3/mod.rs +++ b/esp-hal/src/soc/esp32s3/mod.rs @@ -115,6 +115,8 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { stack_chk_guard.write_volatile(0xdeadbabe); } + crate::interrupt::setup_interrupts(); + // continue with default reset handler xtensa_lx_rt::Reset(); } diff --git a/examples/src/bin/embassy_rmt_rx.rs b/examples/src/bin/embassy_rmt_rx.rs index 7b61478b737..d5e6637e8f8 100644 --- a/examples/src/bin/embassy_rmt_rx.rs +++ b/examples/src/bin/embassy_rmt_rx.rs @@ -18,7 +18,7 @@ use esp_hal::{ gpio::{Gpio5, Output, PushPull, IO}, peripherals::Peripherals, prelude::*, - rmt::{asynch::RxChannelAsync, PulseCode, Rmt, RxChannelConfig, RxChannelCreator}, + rmt::{asynch::RxChannelAsync, PulseCode, Rmt, RxChannelConfig, RxChannelCreatorAsync}, }; use esp_println::{print, println}; @@ -58,7 +58,7 @@ async fn main(spawner: Spawner) { } }; - let rmt = Rmt::new(peripherals.RMT, freq, &clocks).unwrap(); + let rmt = Rmt::new_async(peripherals.RMT, freq, &clocks).unwrap(); let rx_config = RxChannelConfig { clk_divider: 255, idle_threshold: 10000, diff --git a/examples/src/bin/embassy_rmt_tx.rs b/examples/src/bin/embassy_rmt_tx.rs index 9cd84873aff..ded064cb98a 100644 --- a/examples/src/bin/embassy_rmt_tx.rs +++ b/examples/src/bin/embassy_rmt_tx.rs @@ -18,7 +18,7 @@ use esp_hal::{ gpio::IO, peripherals::Peripherals, prelude::*, - rmt::{asynch::TxChannelAsync, PulseCode, Rmt, TxChannelConfig, TxChannelCreator}, + rmt::{asynch::TxChannelAsync, PulseCode, Rmt, TxChannelConfig, TxChannelCreatorAsync}, timer::TimerGroup, }; use esp_println::println; @@ -43,7 +43,7 @@ async fn main(_spawner: Spawner) { } }; - let rmt = Rmt::new(peripherals.RMT, freq, &clocks).unwrap(); + let rmt = Rmt::new_async(peripherals.RMT, freq, &clocks).unwrap(); let mut channel = rmt .channel0 diff --git a/examples/src/bin/hello_rgb.rs b/examples/src/bin/hello_rgb.rs index 96e817e216c..20ba84e88d6 100644 --- a/examples/src/bin/hello_rgb.rs +++ b/examples/src/bin/hello_rgb.rs @@ -56,9 +56,9 @@ fn main() -> ! { // Configure RMT peripheral globally #[cfg(not(feature = "esp32h2"))] - let rmt = Rmt::new(peripherals.RMT, 80.MHz(), &clocks).unwrap(); + let rmt = Rmt::new(peripherals.RMT, 80.MHz(), &clocks, None).unwrap(); #[cfg(feature = "esp32h2")] - let rmt = Rmt::new(peripherals.RMT, 32.MHz(), &clocks).unwrap(); + let rmt = Rmt::new(peripherals.RMT, 32.MHz(), &clocks, None).unwrap(); // We use one of the RMT channels to instantiate a `SmartLedsAdapter` which can // be used directly with all `smart_led` implementations diff --git a/examples/src/bin/rmt_rx.rs b/examples/src/bin/rmt_rx.rs index 69e1123ad73..ab229213470 100644 --- a/examples/src/bin/rmt_rx.rs +++ b/examples/src/bin/rmt_rx.rs @@ -38,7 +38,7 @@ fn main() -> ! { } }; - let rmt = Rmt::new(peripherals.RMT, freq, &clocks).unwrap(); + let rmt = Rmt::new(peripherals.RMT, freq, &clocks, None).unwrap(); let rx_config = RxChannelConfig { clk_divider: 1, diff --git a/examples/src/bin/rmt_tx.rs b/examples/src/bin/rmt_tx.rs index 284324acd1c..8b267ac3fa3 100644 --- a/examples/src/bin/rmt_tx.rs +++ b/examples/src/bin/rmt_tx.rs @@ -33,7 +33,7 @@ fn main() -> ! { } }; - let rmt = Rmt::new(peripherals.RMT, freq, &clocks).unwrap(); + let rmt = Rmt::new(peripherals.RMT, freq, &clocks, None).unwrap(); let tx_config = TxChannelConfig { clk_divider: 255,