diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c0b49bfe13..8159992836f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -162,9 +162,16 @@ jobs: toolchain: nightly components: rustfmt,miri + # Run xtask tests + - name: Run xtask tests + run: cd xtask && cargo test --features release + # Check the formatting of all packages: - run: cargo xtask fmt-packages --check + # Check metadata generation for all packages: + - run: cargo xtask update-metadata --check + # Run tests in esp-config - run: cd esp-config && cargo test --features build,tui diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index c1ad810037b..62f5c09133d 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -177,6 +177,10 @@ jobs: runs-on: ubuntu-latest if: ${{ (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'release-pr')) }} steps: + - uses: dtolnay/rust-toolchain@v1 + with: + toolchain: nightly + targets: riscv32imac-unknown-none-elf - uses: actions/checkout@v4 with: repository: esp-rs/esp-hal diff --git a/documentation/DEVELOPER-GUIDELINES.md b/documentation/DEVELOPER-GUIDELINES.md index 247663b0da2..9f9f37fabe9 100644 --- a/documentation/DEVELOPER-GUIDELINES.md +++ b/documentation/DEVELOPER-GUIDELINES.md @@ -61,6 +61,7 @@ In general, the [Rust API Guidelines](https://rust-lang.github.io/api-guidelines - see [this example](https://github.com/esp-rs/esp-hal/blob/df2b7bd8472cc1d18db0d9441156575570f59bb3/esp-hal/src/spi/mod.rs#L15) - e.g. `#[cfg_attr(feature = "defmt", derive(defmt::Format))]` - Implementations of common, but unstable traits (e.g. `embassy_embedded_hal::SetConfig`) need to be gated with the `unstable` feature. +- Libraries depending on esp-hal, should disable the `rt` feature to avoid future compatibility concerns. ## API Surface diff --git a/esp-backtrace/CHANGELOG.md b/esp-backtrace/CHANGELOG.md index 822c5db751c..3188ca7c16c 100644 --- a/esp-backtrace/CHANGELOG.md +++ b/esp-backtrace/CHANGELOG.md @@ -16,6 +16,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +### Removed + + +## [v0.17.0] - 2025-07-16 + ### Removed - Removed support for ESP32-P4 (#3754) @@ -89,4 +94,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [0.15.1]: https://github.com/esp-rs/esp-hal/releases/tag/esp-backtrace-v0.15.1 [v0.16.0]: https://github.com/esp-rs/esp-hal/compare/esp-backtrace-v0.15.1...esp-backtrace-v0.16.0 -[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-backtrace-v0.16.0...HEAD +[v0.17.0]: https://github.com/esp-rs/esp-hal/compare/esp-backtrace-v0.16.0...esp-backtrace-v0.17.0 +[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-backtrace-v0.17.0...HEAD diff --git a/esp-backtrace/Cargo.toml b/esp-backtrace/Cargo.toml index ab5413c42e8..cb95c4b5731 100644 --- a/esp-backtrace/Cargo.toml +++ b/esp-backtrace/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "esp-backtrace" -version = "0.16.0" +version = "0.17.0" edition = "2024" rust-version = "1.86.0" description = "Bare-metal backtrace support for Espressif devices" @@ -21,13 +21,13 @@ test = false [dependencies] cfg-if = "1.0.0" defmt = { version = "1.0.1", optional = true } -esp-config = { version = "0.4.0", path = "../esp-config" } -esp-println = { version = "0.14.0", optional = true, default-features = false, path = "../esp-println" } +esp-config = { version = "0.5.0", path = "../esp-config" } +esp-println = { version = "0.15.0", optional = true, default-features = false, path = "../esp-println" } heapless = "0.8" semihosting = { version = "0.1.20", optional = true } [build-dependencies] -esp-config = { version = "0.4.0", path = "../esp-config", features = ["build"] } +esp-config = { version = "0.5.0", path = "../esp-config", features = ["build"] } [features] default = ["colors"] diff --git a/esp-bootloader-esp-idf/CHANGELOG.md b/esp-bootloader-esp-idf/CHANGELOG.md index 33c71141e35..b1970fa2cc4 100644 --- a/esp-bootloader-esp-idf/CHANGELOG.md +++ b/esp-bootloader-esp-idf/CHANGELOG.md @@ -10,6 +10,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +### Changed + + +### Fixed + + +### Removed + + +## [v0.2.0] - 2025-07-16 + ### Changed - The `log` feature has been renamed to `log-04` (#3675) @@ -21,9 +32,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed a problem with calculating the otadata checksum (#3629) -### Removed - - ## [v0.1.0] - 2025-06-03 ### Added @@ -38,4 +46,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Update `defmt` to 1.0 (#3416) [v0.1.0]: https://github.com/esp-rs/esp-hal/releases/tag/esp-bootloader-esp-idf-v0.1.0 -[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-bootloader-esp-idf-v0.1.0...HEAD +[v0.2.0]: https://github.com/esp-rs/esp-hal/compare/esp-bootloader-esp-idf-v0.1.0...esp-bootloader-esp-idf-v0.2.0 +[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-bootloader-esp-idf-v0.2.0...HEAD diff --git a/esp-bootloader-esp-idf/Cargo.toml b/esp-bootloader-esp-idf/Cargo.toml index 315beba0218..89d222ac82b 100644 --- a/esp-bootloader-esp-idf/Cargo.toml +++ b/esp-bootloader-esp-idf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "esp-bootloader-esp-idf" -version = "0.1.0" +version = "0.2.0" edition = "2024" rust-version = "1.86.0" description = "Functionality related to the esp-idf bootloader" @@ -21,8 +21,8 @@ test = true cfg-if = "1.0.0" defmt = { version = "1.0.1", optional = true } document-features = "0.2.11" -esp-config = { version = "0.4.0", path = "../esp-config" } -esp-rom-sys = { version = "0.1.0", path = "../esp-rom-sys", optional = true } +esp-config = { version = "0.5.0", path = "../esp-config" } +esp-rom-sys = { version = "0.1.1", path = "../esp-rom-sys", optional = true } embedded-storage = "0.3.1" log-04 = { package = "log", version = "0.4.26", optional = true } strum = { version = "0.27.1", default-features = false, features = ["derive"] } @@ -32,7 +32,7 @@ md-5 = { version = "0.10.6", default-features = false, optional = true } [build-dependencies] jiff = { version = "0.2.13", default-features = false, features = ["std"] } -esp-config = { version = "0.4.0", path = "../esp-config", features = ["build"] } +esp-config = { version = "0.5.0", path = "../esp-config", features = ["build"] } [features] default = ["validation"] diff --git a/esp-bootloader-esp-idf/src/lib.rs b/esp-bootloader-esp-idf/src/lib.rs index fe6b43bbe2a..7c22fd29c09 100644 --- a/esp-bootloader-esp-idf/src/lib.rs +++ b/esp-bootloader-esp-idf/src/lib.rs @@ -153,7 +153,7 @@ pub struct EspAppDesc { impl EspAppDesc { /// Needs to be public since it's used by the macro #[doc(hidden)] - #[allow(clippy::too_many_arguments, reason = "For internal use only")] + #[expect(clippy::too_many_arguments, reason = "For internal use only")] pub const fn new_internal( version: &str, project_name: &str, diff --git a/esp-config/CHANGELOG.md b/esp-config/CHANGELOG.md index ad608afd49f..99b477bdaab 100644 --- a/esp-config/CHANGELOG.md +++ b/esp-config/CHANGELOG.md @@ -9,7 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Add `ESP_HAL_CONFIG_PLACE_RMT_DRIVER_IN_RAM` configuration option to pin the RMT driver in RAM (#3778). ### Changed @@ -20,6 +19,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [v0.5.0] - 2025-07-16 + +### Added + +- Add `ESP_HAL_CONFIG_PLACE_RMT_DRIVER_IN_RAM` configuration option to pin the RMT driver in RAM (#3778) + ## [v0.4.0] - 2025-06-03 ### Added @@ -65,4 +70,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [0.3.1]: https://github.com/esp-rs/esp-hal/releases/tag/esp-config-v0.3.1 [v0.4.0]: https://github.com/esp-rs/esp-hal/compare/esp-config-v0.3.1...esp-config-v0.4.0 -[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-config-v0.4.0...HEAD +[v0.5.0]: https://github.com/esp-rs/esp-hal/compare/esp-config-v0.4.0...esp-config-v0.5.0 +[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-config-v0.5.0...HEAD diff --git a/esp-config/Cargo.toml b/esp-config/Cargo.toml index d292454541a..d91297d32a0 100644 --- a/esp-config/Cargo.toml +++ b/esp-config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "esp-config" -version = "0.4.0" +version = "0.5.0" edition = "2024" rust-version = "1.86.0" description = "Configure projects using esp-hal and related packages" @@ -23,8 +23,8 @@ document-features = "0.2.11" serde = { version = "1.0.197", default-features = false, features = ["derive"], optional = true } serde_yaml = { version = "0.9", optional = true } evalexpr = { version = "12.0.2", optional = true } -esp-metadata = { version = "0.7.0", path = "../esp-metadata", features = ["clap"], optional = true } -esp-metadata-generated = { version = "0.0.1", path = "../esp-metadata-generated", features = ["build-script"], optional = true } +esp-metadata = { version = "0.8.0", path = "../esp-metadata", features = ["clap"], optional = true } +esp-metadata-generated = { version = "0.1.0", path = "../esp-metadata-generated", features = ["build-script"], optional = true } # used by the `tui` feature clap = { version = "4.5.32", features = ["derive"], optional = true } diff --git a/esp-config/src/generate/mod.rs b/esp-config/src/generate/mod.rs index 719989d58a6..325db20419d 100644 --- a/esp-config/src/generate/mod.rs +++ b/esp-config/src/generate/mod.rs @@ -126,8 +126,6 @@ pub struct CfgConstraint { /// Generate the config from a YAML definition. /// -/// The YAML follows the format outlined by [Config]. -/// /// After deserializing the config and normalizing it, this will call /// [generate_config] to finally get the currently active configuration. pub fn generate_config_from_yaml_definition( diff --git a/esp-hal-embassy/CHANGELOG.md b/esp-hal-embassy/CHANGELOG.md index ec3c9a28d1a..7e39a289fad 100644 --- a/esp-hal-embassy/CHANGELOG.md +++ b/esp-hal-embassy/CHANGELOG.md @@ -9,11 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- `Executor::run_with_callbacks` and the associated `Callbacks` trait (#3737) ### Changed -- MSRV is now 1.88.0 (#3742) ### Fixed @@ -21,6 +19,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [v0.9.0] - 2025-07-16 + +### Added + +- `Executor::run_with_callbacks` and the associated `Callbacks` trait (#3737) + +### Changed + +- MSRV is now 1.88.0 (#3742) + ## [v0.8.1] - 2025-06-05 ### Fixed @@ -130,4 +138,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [0.7.0]: https://github.com/esp-rs/esp-hal/releases/tag/esp-hal-embassy-v0.7.0 [v0.8.0]: https://github.com/esp-rs/esp-hal/compare/esp-hal-embassy-v0.7.0...esp-hal-embassy-v0.8.0 [v0.8.1]: https://github.com/esp-rs/esp-hal/compare/esp-hal-embassy-v0.8.0...esp-hal-embassy-v0.8.1 -[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-hal-embassy-v0.8.1...HEAD +[v0.9.0]: https://github.com/esp-rs/esp-hal/compare/esp-hal-embassy-v0.8.1...esp-hal-embassy-v0.9.0 +[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-hal-embassy-v0.9.0...HEAD diff --git a/esp-hal-embassy/Cargo.toml b/esp-hal-embassy/Cargo.toml index 2fb26c7ccf4..edad5a5b53b 100644 --- a/esp-hal-embassy/Cargo.toml +++ b/esp-hal-embassy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "esp-hal-embassy" -version = "0.8.1" +version = "0.9.0" edition = "2024" rust-version = "1.88.0" description = "Embassy support for esp-hal" @@ -21,7 +21,7 @@ test = false [dependencies] cfg-if = "1.0.0" critical-section = "1.2.0" -esp-hal = { version = "1.0.0-beta.1", path = "../esp-hal", features = ["requires-unstable"] } +esp-hal = { version = "1.0.0-rc.0", path = "../esp-hal", default-features = false, features = ["requires-unstable"] } portable-atomic = "1.11.0" static_cell = "2.1.0" @@ -31,8 +31,8 @@ embassy-sync = { version = "0.6.2" } embassy-time = { version = "0.4.0" } embassy-time-driver = { version = "0.2.0", features = [ "tick-hz-1_000_000" ] } embassy-time-queue-utils = { version = "0.1.0", features = ["_generic-queue"] } -esp-config = { version = "0.4.0", path = "../esp-config" } -macros = { version = "0.18.0", features = ["embassy"], package = "esp-hal-procmacros", path = "../esp-hal-procmacros" } +esp-config = { version = "0.5.0", path = "../esp-config" } +macros = { version = "0.19.0", features = ["embassy"], package = "esp-hal-procmacros", path = "../esp-hal-procmacros" } # Optional dependencies that enable ecosystem support. embassy-executor = { version = "0.7.0", features = ["timer-item-payload-size-4"], optional = true } @@ -42,8 +42,8 @@ defmt = { version = "1.0.1", optional = true } log-04 = { package = "log", version = "0.4.27", optional = true } [build-dependencies] -esp-config = { version = "0.4.0", path = "../esp-config", features = ["build"] } -esp-metadata-generated = { version = "0.0.1", path = "../esp-metadata-generated", features = ["build-script"] } +esp-config = { version = "0.5.0", path = "../esp-config", features = ["build"] } +esp-metadata-generated = { version = "0.1.0", path = "../esp-metadata-generated", features = ["build-script"] } [features] default = ["executors"] diff --git a/esp-hal-embassy/MIGRATING-0.8.0.md b/esp-hal-embassy/MIGRATING-0.8.0.md index 3b07314d620..3c2ef9d3cfc 100644 --- a/esp-hal-embassy/MIGRATING-0.8.0.md +++ b/esp-hal-embassy/MIGRATING-0.8.0.md @@ -1 +1 @@ -# Migration Guide from 0.8.0 to {{currentVersion}} +# Migration Guide from 0.8.0 to 0.9.0 diff --git a/esp-hal-procmacros/CHANGELOG.md b/esp-hal-procmacros/CHANGELOG.md index 51cdc1c59f1..a78b7723426 100644 --- a/esp-hal-procmacros/CHANGELOG.md +++ b/esp-hal-procmacros/CHANGELOG.md @@ -9,14 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Added simplified conditional documentation using the `#[enable_doc_switch]` macro (#3630) -- `error!` and `warning!` (moved from `esp-build`) (#3645) -- Added `doc_replace` macro (#3744) ### Changed -- MSRV is now 1.88.0 (#3742) -- The `handler` macro no longer accepts priority as a string (#3643) ### Fixed @@ -24,6 +19,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [v0.19.0] - 2025-07-16 + +### Added + +- Added simplified conditional documentation using the `#[enable_doc_switch]` macro (#3630) +- `error!` and `warning!` (moved from `esp-build`) (#3645) +- Added `doc_replace` macro (#3744) + +### Changed + +- MSRV is now 1.88.0 (#3742) +- The `handler` macro no longer accepts priority as a string (#3643) + ## [v0.18.0] - 2025-06-03 ### Changed @@ -94,4 +102,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [0.17.0]: https://github.com/esp-rs/esp-hal/releases/tag/esp-hal-procmacros-v0.17.0 [v0.18.0]: https://github.com/esp-rs/esp-hal/compare/esp-hal-procmacros-v0.17.0...esp-hal-procmacros-v0.18.0 -[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-hal-procmacros-v0.18.0...HEAD +[v0.19.0]: https://github.com/esp-rs/esp-hal/compare/esp-hal-procmacros-v0.18.0...esp-hal-procmacros-v0.19.0 +[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-hal-procmacros-v0.19.0...HEAD diff --git a/esp-hal-procmacros/Cargo.toml b/esp-hal-procmacros/Cargo.toml index c7b24b19903..a929841554d 100644 --- a/esp-hal-procmacros/Cargo.toml +++ b/esp-hal-procmacros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "esp-hal-procmacros" -version = "0.18.0" +version = "0.19.0" edition = "2024" rust-version = "1.88.0" description = "Procedural macros for esp-hal" diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 401b05ec082..c693ad560d8 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -9,6 +9,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- A reimplemntation of the `assign_resources!` macro (#3809) + +### Changed + + +### Fixed + +- PSRAM on ESP32-S2 (#3811) +- WDT now allows configuring longer timeouts (#3816) + +### Removed + + +## [v1.0.0-rc.0] - 2025-07-16 + +### Added + - `i2c::master::BusTimeout::Disabled` for ESP32-S2 (#3591) - The `const CHANNEL: u8` parameter of RMT channels can now be erased via `Channel::degrade()`. (#3505) - ESP32-C6: GPIO6 now implements `AnalogPin` (#3668) @@ -17,7 +34,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added GPIO11-GPIO17 to ESP32-C2. (#3726) - Added the feature `requires-unstable` (#3772) - `AnyPin::downcast`/`AnyPeripheral::downcast` to allow retrieving the original GPIO/peripheral type (#3783, #3784) -- Add `ESP_HAL_CONFIG_PLACE_RMT_DRIVER_IN_RAM` configuration option to pin the RMT driver in RAM (#3778). +- Add `ESP_HAL_CONFIG_PLACE_RMT_DRIVER_IN_RAM` configuration option to pin the RMT driver in RAM (#3778) +- The `rt` feature (#3706) ### Changed @@ -35,6 +53,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Adjusted ESP32-S2 and ESP-S3 memory region lengths to reflect those defined in ESP-IDF. (#3709) - Changed the various `ConfigError` variant names to use a consistent word order. (#3782) - Adjusted ESP32-S2 deep-sleep to hibernate for the Ext1WakeupSource (#3785) +- Libraries depending on esp-hal should now disable default features, so that only the final binary crate enables the `rt` feature (#3706) +- Changed `interrupt::RESERVED_INTERRUPTS` from `&[usize]` to `&[u32]` (#3798) ### Fixed @@ -1297,4 +1317,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [0.23.1]: https://github.com/esp-rs/esp-hal/compare/v0.23.0...v0.23.1 [v1.0.0-beta.0]: https://github.com/esp-rs/esp-hal/compare/v0.23.1...esp-hal-v1.0.0-beta.0 [v1.0.0-beta.1]: https://github.com/esp-rs/esp-hal/compare/esp-hal-v1.0.0-beta.0...esp-hal-v1.0.0-beta.1 -[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-hal-v1.0.0-beta.1...HEAD +[v1.0.0-rc.0]: https://github.com/esp-rs/esp-hal/compare/esp-hal-v1.0.0-beta.1...esp-hal-v1.0.0-rc.0 +[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-hal-v1.0.0-rc.0...HEAD diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml index 25b04dba9ed..3518e3f5fb9 100644 --- a/esp-hal/Cargo.toml +++ b/esp-hal/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "esp-hal" -version = "1.0.0-beta.1" +version = "1.0.0-rc.0" edition = "2024" rust-version = "1.88.0" description = "Bare-metal HAL for Espressif devices" @@ -31,7 +31,7 @@ enumset = "1.1.6" paste = "1.0.15" portable-atomic = { version = "1.11.0", default-features = false } -esp-rom-sys = { version = "0.1.0", path = "../esp-rom-sys" } +esp-rom-sys = { version = "0.1.1", path = "../esp-rom-sys" } # Unstable dependencies that are not (strictly) part of the public API bitfield = "0.19.0" @@ -43,9 +43,9 @@ fugit = "0.3.7" instability = "0.3.7" strum = { version = "0.27.1", default-features = false, features = ["derive"] } -esp-config = { version = "0.4.0", path = "../esp-config" } -esp-metadata-generated = { version = "0.0.1", path = "../esp-metadata-generated" } -procmacros = { version = "0.18.0", package = "esp-hal-procmacros", path = "../esp-hal-procmacros" } +esp-config = { version = "0.5.0", path = "../esp-config" } +esp-metadata-generated = { version = "0.1.0", path = "../esp-metadata-generated" } +procmacros = { version = "0.19.0", package = "esp-hal-procmacros", path = "../esp-hal-procmacros" } # Dependencies that are optional because they are used by unstable drivers. # They are needed when using the `unstable` feature. @@ -73,33 +73,33 @@ ufmt-write = { version = "0.1.0", optional = true } # IMPORTANT: # Each supported device MUST have its PAC included below along with a # corresponding feature. -esp32 = { version = "0.37.0", features = ["critical-section", "rt"], git = "https://github.com/esp-rs/esp-pacs", rev = "782de0b", optional = true } -esp32c2 = { version = "0.26.0", features = ["critical-section", "rt"], git = "https://github.com/esp-rs/esp-pacs", rev = "782de0b", optional = true } -esp32c3 = { version = "0.29.0", features = ["critical-section", "rt"], git = "https://github.com/esp-rs/esp-pacs", rev = "782de0b", optional = true } -esp32c6 = { version = "0.20.0", features = ["critical-section", "rt"], git = "https://github.com/esp-rs/esp-pacs", rev = "782de0b", optional = true } -esp32h2 = { version = "0.16.0", features = ["critical-section", "rt"], git = "https://github.com/esp-rs/esp-pacs", rev = "782de0b", optional = true } -esp32s2 = { version = "0.28.0", features = ["critical-section", "rt"], git = "https://github.com/esp-rs/esp-pacs", rev = "782de0b", optional = true } -esp32s3 = { version = "0.32.0", features = ["critical-section", "rt"], git = "https://github.com/esp-rs/esp-pacs", rev = "782de0b", optional = true } +esp32 = { version = "0.38.0", features = ["critical-section", "rt"], optional = true, git = "https://github.com/esp-rs/esp-pacs", rev = "7232b3e" } +esp32c2 = { version = "0.27.0", features = ["critical-section", "rt"], optional = true, git = "https://github.com/esp-rs/esp-pacs", rev = "7232b3e" } +esp32c3 = { version = "0.30.0", features = ["critical-section", "rt"], optional = true, git = "https://github.com/esp-rs/esp-pacs", rev = "7232b3e" } +esp32c6 = { version = "0.21.0", features = ["critical-section", "rt"], optional = true, git = "https://github.com/esp-rs/esp-pacs", rev = "7232b3e" } +esp32h2 = { version = "0.17.0", features = ["critical-section", "rt"], optional = true, git = "https://github.com/esp-rs/esp-pacs", rev = "7232b3e" } +esp32s2 = { version = "0.29.0", features = ["critical-section", "rt"], optional = true, git = "https://github.com/esp-rs/esp-pacs", rev = "7232b3e" } +esp32s3 = { version = "0.33.0", features = ["critical-section", "rt"], optional = true, git = "https://github.com/esp-rs/esp-pacs", rev = "7232b3e" } [target.'cfg(target_arch = "riscv32")'.dependencies] riscv = { version = "0.12.1" } -esp-riscv-rt = { version = "0.11.0", path = "../esp-riscv-rt" } +esp-riscv-rt = { version = "0.12.0", path = "../esp-riscv-rt", optional = true } [target.'cfg(target_arch = "xtensa")'.dependencies] -xtensa-lx = { version = "0.11.0", path = "../xtensa-lx" } -xtensa-lx-rt = { version = "0.19.0", path = "../xtensa-lx-rt" } +xtensa-lx = { version = "0.12.0", path = "../xtensa-lx" } +xtensa-lx-rt = { version = "0.20.0", path = "../xtensa-lx-rt", optional = true } [build-dependencies] cfg-if = "1.0.0" -esp-metadata-generated = { version = "0.0.1", path = "../esp-metadata-generated", features = ["build-script"] } -esp-config = { version = "0.4.0", path = "../esp-config", features = ["build"] } +esp-metadata-generated = { version = "0.1.0", path = "../esp-metadata-generated", features = ["build-script"] } +esp-config = { version = "0.5.0", path = "../esp-config", features = ["build"] } serde = { version = "1.0.219", default-features = false, features = ["derive"] } [dev-dependencies] jiff = { version = "0.2.10", default-features = false, features = ["static"] } [features] -default = [] +default = ["rt"] # These features are considered private and unstable. They are not covered by # semver guarantees and may change or be removed without notice. @@ -174,6 +174,21 @@ esp32s3 = [ "esp-metadata-generated/esp32s3", ] +## Runtime support +## +## If you are depending on `esp-hal` as a library, you should *not* enable the `rt` feature under any circumstance. +rt = [ + "dep:xtensa-lx-rt", + "dep:esp-riscv-rt", + "esp32?/rt", + "esp32c2?/rt", + "esp32c3?/rt", + "esp32c6?/rt", + "esp32h2?/rt", + "esp32s2?/rt", + "esp32s3?/rt", +] + #! ### Logging Feature Flags ## Enable logging output using version 0.4 of the `log` crate. diff --git a/esp-hal/MIGRATING-1.0.0-beta.1.md b/esp-hal/MIGRATING-1.0.0-beta.1.md index 0634817b55d..f6652e62900 100644 --- a/esp-hal/MIGRATING-1.0.0-beta.1.md +++ b/esp-hal/MIGRATING-1.0.0-beta.1.md @@ -1,4 +1,4 @@ -# Migration Guide from 1.0.0-beta.1 to {{currentVersion}} +# Migration Guide from 1.0.0-beta.1 to 1.0.0-rc.0 ## AnyI2c and AnySpi have been moved to mode-specific submodules diff --git a/esp-hal/README.md b/esp-hal/README.md index 6a6a9d9b72c..d4b9d488979 100644 --- a/esp-hal/README.md +++ b/esp-hal/README.md @@ -64,6 +64,7 @@ For help getting started with this HAL, please refer to [The Rust on ESP Book] a | GPIO | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | | HMAC | | | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | | I2C master | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | +| LP I2C master | | | | ⚒️ | | | | | I2C slave | ❌ | | ❌ | ❌ | ❌ | ❌ | ❌ | | I2S | ⚒️ | | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | | Interrupts | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | @@ -90,6 +91,7 @@ For help getting started with this HAL, please refer to [The Rust on ESP Book] a | Touch | ⚒️ | | | | | ❌ | ❌ | | TWAI | ⚒️ | | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | | UART | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | +| LP UART | | | | ⚒️ | | | | | ULP (FSM) | ⚒️ | | | | | ⚒️ | ⚒️ | | ULP (RISC-V) | | | | ⚒️ | | ⚒️ | ⚒️ | | USB OTG FS | | | | | | ⚒️ | ⚒️ | diff --git a/esp-hal/api-baseline/esp32.json.gz b/esp-hal/api-baseline/esp32.json.gz index faf69ab2261..283e25fc142 100644 Binary files a/esp-hal/api-baseline/esp32.json.gz and b/esp-hal/api-baseline/esp32.json.gz differ diff --git a/esp-hal/api-baseline/esp32c2.json.gz b/esp-hal/api-baseline/esp32c2.json.gz index 9a12a8e5480..801f66498db 100644 Binary files a/esp-hal/api-baseline/esp32c2.json.gz and b/esp-hal/api-baseline/esp32c2.json.gz differ diff --git a/esp-hal/api-baseline/esp32c3.json.gz b/esp-hal/api-baseline/esp32c3.json.gz index 665c6818e4c..2dd307ffb5c 100644 Binary files a/esp-hal/api-baseline/esp32c3.json.gz and b/esp-hal/api-baseline/esp32c3.json.gz differ diff --git a/esp-hal/api-baseline/esp32c6.json.gz b/esp-hal/api-baseline/esp32c6.json.gz index 40cf104db95..8758385d2a8 100644 Binary files a/esp-hal/api-baseline/esp32c6.json.gz and b/esp-hal/api-baseline/esp32c6.json.gz differ diff --git a/esp-hal/api-baseline/esp32h2.json.gz b/esp-hal/api-baseline/esp32h2.json.gz index a2a5db2a5a3..28893b25eb4 100644 Binary files a/esp-hal/api-baseline/esp32h2.json.gz and b/esp-hal/api-baseline/esp32h2.json.gz differ diff --git a/esp-hal/api-baseline/esp32s2.json.gz b/esp-hal/api-baseline/esp32s2.json.gz index 5377318387a..0d529d7f5c6 100644 Binary files a/esp-hal/api-baseline/esp32s2.json.gz and b/esp-hal/api-baseline/esp32s2.json.gz differ diff --git a/esp-hal/api-baseline/esp32s3.json.gz b/esp-hal/api-baseline/esp32s3.json.gz index b88ccba666e..9a39120c6b7 100644 Binary files a/esp-hal/api-baseline/esp32s3.json.gz and b/esp-hal/api-baseline/esp32s3.json.gz differ diff --git a/esp-hal/build.rs b/esp-hal/build.rs index 0c883ffad86..1c0cef63865 100644 --- a/esp-hal/build.rs +++ b/esp-hal/build.rs @@ -1,7 +1,8 @@ +use std::error::Error; +#[cfg(feature = "rt")] use std::{ collections::HashMap, env, - error::Error, fs::{self, File}, io::{BufRead, Write}, path::{Path, PathBuf}, @@ -55,11 +56,6 @@ fn main() -> Result<(), Box> { // Define all necessary configuration symbols for the configured device: chip.define_cfgs(); - // Place all linker scripts in `OUT_DIR`, and instruct Cargo how to find these - // files: - let out = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - println!("cargo:rustc-link-search={}", out.display()); - // emit config println!("cargo:rerun-if-changed=./esp_config.yml"); let cfg_yaml = std::fs::read_to_string("./esp_config.yml") @@ -77,18 +73,27 @@ fn main() -> Result<(), Box> { } } - if chip.is_xtensa() { - #[cfg(any(feature = "esp32", feature = "esp32s2"))] - File::create(out.join("memory_extras.x"))?.write_all(&generate_memory_extras())?; + // Only emit linker directives if the `rt` feature is enabled + #[cfg(feature = "rt")] + { + // Place all linker scripts in `OUT_DIR`, and instruct Cargo how to find these + // files: + let out = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let (irtc, drtc) = if cfg!(feature = "esp32s3") { - ("rtc_fast_seg", "rtc_fast_seg") - } else { - ("rtc_fast_iram_seg", "rtc_fast_dram_seg") - }; + println!("cargo:rustc-link-search={}", out.display()); + + if chip.is_xtensa() { + #[cfg(any(feature = "esp32", feature = "esp32s2"))] + File::create(out.join("memory_extras.x"))?.write_all(&generate_memory_extras())?; - let alias = format!( - r#" + let (irtc, drtc) = if cfg!(feature = "esp32s3") { + ("rtc_fast_seg", "rtc_fast_seg") + } else { + ("rtc_fast_iram_seg", "rtc_fast_dram_seg") + }; + + let alias = format!( + r#" REGION_ALIAS("ROTEXT", irom_seg); REGION_ALIAS("RWTEXT", iram_seg); REGION_ALIAS("RODATA", drom_seg); @@ -96,38 +101,39 @@ fn main() -> Result<(), Box> { REGION_ALIAS("RTC_FAST_RWTEXT", {irtc}); REGION_ALIAS("RTC_FAST_RWDATA", {drtc}); "# - ); + ); - 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, - &cfg, - "ld/riscv/asserts.x", - out.join("asserts.x"), - )?; - preprocess_file( - &config_symbols, - &cfg, - "ld/riscv/hal-defaults.x", - out.join("hal-defaults.x"), - )?; - } + fs::write(out.join("alias.x"), alias)?; + fs::copy("ld/xtensa/hal-defaults.x", out.join("hal-defaults.x"))?; + } else { + // RISC-V devices: - // 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, &cfg, "ld/sections", &out)?; - copy_dir_all(&config_symbols, &cfg, format!("ld/{}", chip.name()), &out)?; + preprocess_file( + &config_symbols, + &cfg, + "ld/riscv/asserts.x", + out.join("asserts.x"), + )?; + preprocess_file( + &config_symbols, + &cfg, + "ld/riscv/hal-defaults.x", + out.join("hal-defaults.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, &cfg, "ld/sections", &out)?; + copy_dir_all(&config_symbols, &cfg, format!("ld/{}", chip.name()), &out)?; + } Ok(()) } // ---------------------------------------------------------------------------- // Helper Functions - +#[cfg(feature = "rt")] fn copy_dir_all( config_symbols: &[&str], cfg: &HashMap, @@ -158,6 +164,7 @@ fn copy_dir_all( } /// A naive pre-processor for linker scripts +#[cfg(feature = "rt")] fn preprocess_file( config: &[&str], cfg: &HashMap, @@ -200,6 +207,7 @@ fn preprocess_file( Ok(()) } +#[cfg(feature = "rt")] fn substitute_config(cfg: &HashMap, line: &str) -> String { let mut result = String::new(); let mut chars = line.chars().peekable(); @@ -237,7 +245,7 @@ fn substitute_config(cfg: &HashMap, line: &str) -> String { result } -#[cfg(feature = "esp32")] +#[cfg(all(feature = "esp32", feature = "rt"))] fn generate_memory_extras() -> Vec { let reserve_dram = if cfg!(feature = "__bluetooth") { "0x10000" @@ -255,7 +263,7 @@ fn generate_memory_extras() -> Vec { .to_vec() } -#[cfg(feature = "esp32s2")] +#[cfg(all(feature = "esp32s2", feature = "rt"))] fn generate_memory_extras() -> Vec { let reserved_cache = if cfg!(feature = "psram") { "0x4000" diff --git a/esp-hal/src/analog/adc/mod.rs b/esp-hal/src/analog/adc/mod.rs index c64a7cf3cc4..2934c428daa 100644 --- a/esp-hal/src/analog/adc/mod.rs +++ b/esp-hal/src/analog/adc/mod.rs @@ -104,7 +104,6 @@ pub struct AdcPin { /// The underlying GPIO pin pub pin: PIN, /// Calibration scheme used for the configured ADC pin - #[cfg_attr(esp32, allow(unused))] pub cal_scheme: CS, _phantom: PhantomData, } @@ -112,7 +111,7 @@ pub struct AdcPin { /// Configuration for the ADC. #[cfg(feature = "unstable")] pub struct AdcConfig { - #[cfg_attr(not(esp32), allow(unused))] + #[cfg_attr(not(esp32), expect(unused))] resolution: Resolution, attenuations: [Option; NUM_ATTENS], _phantom: PhantomData, diff --git a/esp-hal/src/assist_debug.rs b/esp-hal/src/assist_debug.rs index 8080c35405f..3e2c0a25bea 100644 --- a/esp-hal/src/assist_debug.rs +++ b/esp-hal/src/assist_debug.rs @@ -78,77 +78,88 @@ impl DebugAssist<'_> { /// Enable SP monitoring on main core. When the SP exceeds the /// `lower_bound` or `upper_bound` threshold, the module will record the PC /// pointer and generate an interrupt. - pub fn enable_sp_monitor(&mut self, lower_bound: u32, upper_bound: u32) { - self.regs() - .core_0_sp_min() - .write(|w| unsafe { w.core_0_sp_min().bits(lower_bound) }); - - self.regs() - .core_0_sp_max() - .write(|w| unsafe { w.core_0_sp_max().bits(upper_bound) }); - - self.regs().core_0_montr_ena().modify(|_, w| { - w.core_0_sp_spill_min_ena() - .set_bit() - .core_0_sp_spill_max_ena() - .set_bit() + pub fn internal_sp_monitor(&mut self, cpu: usize, lower_bound: u32, upper_bound: u32) { + let regs = self.regs().cpu(cpu); + + regs.sp_min() + .write(|w| unsafe { w.sp_min().bits(lower_bound) }); + + regs.sp_max() + .write(|w| unsafe { w.sp_max().bits(upper_bound) }); + + regs.montr_ena().modify(|_, w| { + w.sp_spill_min_ena().set_bit(); + w.sp_spill_max_ena().set_bit() }); - self.clear_sp_monitor_interrupt(); + regs.intr_clr().write(|w| { + w.sp_spill_max_clr().set_bit(); + w.sp_spill_min_clr().set_bit() + }); - self.regs().core_0_intr_ena().modify(|_, w| { - w.core_0_sp_spill_max_intr_ena() - .set_bit() - .core_0_sp_spill_min_intr_ena() - .set_bit() + regs.intr_ena().modify(|_, w| { + w.sp_spill_max_intr_ena().set_bit(); + w.sp_spill_min_intr_ena().set_bit() }); } - /// Disable SP monitoring on main core. - pub fn disable_sp_monitor(&mut self) { - self.regs().core_0_intr_ena().modify(|_, w| { - w.core_0_sp_spill_max_intr_ena() - .clear_bit() - .core_0_sp_spill_min_intr_ena() - .clear_bit() + fn internal_disable_sp_monitor(&mut self, cpu: usize) { + let regs = self.regs().cpu(cpu); + + regs.intr_ena().modify(|_, w| { + w.sp_spill_max_intr_ena().clear_bit(); + w.sp_spill_min_intr_ena().clear_bit() }); - self.regs().core_0_montr_ena().modify(|_, w| { - w.core_0_sp_spill_min_ena() - .clear_bit() - .core_0_sp_spill_max_ena() - .clear_bit() + regs.montr_ena().modify(|_, w| { + w.sp_spill_min_ena().clear_bit(); + w.sp_spill_max_ena().clear_bit() }); } + fn internal_clear_sp_monitor_interrupt(&mut self, cpu: usize) { + self.regs().cpu(cpu).intr_clr().write(|w| { + w.sp_spill_max_clr().set_bit(); + w.sp_spill_min_clr().set_bit() + }); + } + + fn internal_is_sp_monitor_interrupt_set(&self, cpu: usize) -> bool { + let regs = self.regs().cpu(cpu); + let intrs = regs.intr_raw().read(); + + intrs.sp_spill_max_raw().bit_is_set() || intrs.sp_spill_min_raw().bit_is_set() + } + + fn internal_sp_monitor_pc(&self, cpu: usize) -> u32 { + self.regs().cpu(cpu).sp_pc().read().sp_pc().bits() + } + + /// Enable SP monitoring on main core. When the SP exceeds the + /// `lower_bound` or `upper_bound` threshold, the module will record the PC + /// pointer and generate an interrupt. + pub fn enable_sp_monitor(&mut self, lower_bound: u32, upper_bound: u32) { + self.internal_sp_monitor(0, lower_bound, upper_bound); + } + + /// Disable SP monitoring on main core. + pub fn disable_sp_monitor(&mut self) { + self.internal_disable_sp_monitor(0) + } + /// Clear SP monitoring interrupt on main core. pub fn clear_sp_monitor_interrupt(&mut self) { - self.regs().core_0_intr_clr().write(|w| { - w.core_0_sp_spill_max_clr() - .set_bit() - .core_0_sp_spill_min_clr() - .set_bit() - }); + self.internal_clear_sp_monitor_interrupt(0) } /// Check, if SP monitoring interrupt is set on main core. pub fn is_sp_monitor_interrupt_set(&self) -> bool { - self.regs() - .core_0_intr_raw() - .read() - .core_0_sp_spill_max_raw() - .bit_is_set() - || self - .regs() - .core_0_intr_raw() - .read() - .core_0_sp_spill_min_raw() - .bit_is_set() + self.internal_is_sp_monitor_interrupt_set(0) } /// Get SP monitoring PC value on main core. pub fn sp_monitor_pc(&self) -> u32 { - self.regs().core_0_sp_pc().read().core_0_sp_pc().bits() + self.internal_sp_monitor_pc(0) } } @@ -158,157 +169,183 @@ impl<'d> DebugAssist<'d> { /// `lower_bound` or `upper_bound` threshold, the module will record the PC /// pointer and generate an interrupt. pub fn enable_core1_sp_monitor(&mut self, lower_bound: u32, upper_bound: u32) { - self.regs() - .core_1_sp_min - .write(|w| w.core_1_sp_min().bits(lower_bound)); - - self.regs() - .core_1_sp_max - .write(|w| w.core_1_sp_max().bits(upper_bound)); - - self.regs().core_1_montr_ena.modify(|_, w| { - w.core_1_sp_spill_min_ena() - .set_bit() - .core_1_sp_spill_max_ena() - .set_bit() - }); - - self.clear_core1_sp_monitor_interrupt(); - - self.regs().core_1_intr_ena.modify(|_, w| { - w.core_1_sp_spill_max_intr_ena() - .set_bit() - .core_1_sp_spill_min_intr_ena() - .set_bit() - }); + self.internal_sp_monitor(1, lower_bound, upper_bound); } /// Disable SP monitoring on secondary core. pub fn disable_core1_sp_monitor(&mut self) { - self.regs().core_1_intr_ena.modify(|_, w| { - w.core_1_sp_spill_max_intr_ena() - .clear_bit() - .core_1_sp_spill_min_intr_ena() - .clear_bit() - }); - - self.regs().core_1_montr_ena.modify(|_, w| { - w.core_1_sp_spill_min_ena() - .clear_bit() - .core_1_sp_spill_max_ena() - .clear_bit() - }); + self.internal_disable_sp_monitor(1) } /// Clear SP monitoring interrupt on secondary core. pub fn clear_core1_sp_monitor_interrupt(&mut self) { - self.regs().core_1_intr_clr.write(|w| { - w.core_1_sp_spill_max_clr() - .set_bit() - .core_1_sp_spill_min_clr() - .set_bit() - }); + self.internal_clear_sp_monitor_interrupt(1) } /// Check, if SP monitoring interrupt is set on secondary core. pub fn is_core1_sp_monitor_interrupt_set(&self) -> bool { - self.regs() - .core_1_intr_raw - .read() - .core_1_sp_spill_max_raw() - .bit_is_set() - || self - .regs() - .core_1_intr_raw - .read() - .core_1_sp_spill_min_raw() - .bit_is_set() + self.internal_is_sp_monitor_interrupt_set(1) } /// Get SP monitoring PC value on secondary core. pub fn core1_sp_monitor_pc(&self) -> u32 { - self.regs().core_1_sp_pc.read().core_1_sp_pc().bits() + self.internal_sp_monitor_pc(1) } } #[cfg(assist_debug_has_region_monitor)] impl DebugAssist<'_> { - /// Enable region monitoring of read/write performed by the main CPU in a - /// certain memory region0. Whenever the bus reads or writes in the - /// specified memory region, an interrupt will be triggered. Two memory - /// regions (region0, region1) can be monitored at the same time. - pub fn enable_region0_monitor( + fn internal_enable_region0_monitor( &mut self, + cpu: usize, lower_bound: u32, upper_bound: u32, reads: bool, writes: bool, ) { - self.regs() - .core_0_area_dram0_0_min() - .write(|w| unsafe { w.core_0_area_dram0_0_min().bits(lower_bound) }); - - self.regs() - .core_0_area_dram0_0_max() - .write(|w| unsafe { w.core_0_area_dram0_0_max().bits(upper_bound) }); - - self.regs().core_0_montr_ena().modify(|_, w| { - w.core_0_area_dram0_0_rd_ena() - .bit(reads) - .core_0_area_dram0_0_wr_ena() - .bit(writes) + let regs = self.regs().cpu(cpu); + + regs.area_dram0_0_min() + .write(|w| unsafe { w.area_dram0_0_min().bits(lower_bound) }); + + regs.area_dram0_0_max() + .write(|w| unsafe { w.area_dram0_0_max().bits(upper_bound) }); + + regs.montr_ena().modify(|_, w| { + w.area_dram0_0_rd_ena().bit(reads); + w.area_dram0_0_wr_ena().bit(writes) }); - self.clear_region0_monitor_interrupt(); + regs.intr_clr().write(|w| { + w.area_dram0_0_rd_clr().set_bit(); + w.area_dram0_0_wr_clr().set_bit() + }); - self.regs().core_0_intr_ena().modify(|_, w| { - w.core_0_area_dram0_0_rd_intr_ena() - .set_bit() - .core_0_area_dram0_0_wr_intr_ena() - .set_bit() + regs.intr_ena().modify(|_, w| { + w.area_dram0_0_rd_intr_ena().set_bit(); + w.area_dram0_0_wr_intr_ena().set_bit() }); } - /// Disable region0 monitoring on main core. - pub fn disable_region0_monitor(&mut self) { - self.regs().core_0_intr_ena().modify(|_, w| { - w.core_0_area_dram0_0_rd_intr_ena() - .clear_bit() - .core_0_area_dram0_0_wr_intr_ena() - .clear_bit() + fn internal_disable_region0_monitor(&mut self, cpu: usize) { + let regs = self.regs().cpu(cpu); + + regs.intr_ena().modify(|_, w| { + w.area_dram0_0_rd_intr_ena().clear_bit(); + w.area_dram0_0_wr_intr_ena().clear_bit() }); - self.regs().core_0_montr_ena().modify(|_, w| { - w.core_0_area_dram0_0_rd_ena() - .clear_bit() - .core_0_area_dram0_0_wr_ena() - .clear_bit() + regs.montr_ena().modify(|_, w| { + w.area_dram0_0_rd_ena().clear_bit(); + w.area_dram0_0_wr_ena().clear_bit() }); } + fn internal_clear_region0_monitor_interrupt(&mut self, cpu: usize) { + self.regs().cpu(cpu).intr_clr().write(|w| { + w.area_dram0_0_rd_clr().set_bit(); + w.area_dram0_0_wr_clr().set_bit() + }); + } + + fn internal_is_region0_monitor_interrupt_set(&self, cpu: usize) -> bool { + let regs = self.regs().cpu(cpu); + let intrs = regs.intr_raw().read(); + + intrs.area_dram0_0_rd_raw().bit_is_set() || intrs.area_dram0_0_wr_raw().bit_is_set() + } + + fn internal_enable_region1_monitor( + &mut self, + cpu: usize, + lower_bound: u32, + upper_bound: u32, + reads: bool, + writes: bool, + ) { + let regs = self.regs().cpu(cpu); + + regs.area_dram0_1_min() + .write(|w| unsafe { w.area_dram0_1_min().bits(lower_bound) }); + + regs.area_dram0_1_max() + .write(|w| unsafe { w.area_dram0_1_max().bits(upper_bound) }); + + regs.montr_ena().modify(|_, w| { + w.area_dram0_1_rd_ena().bit(reads); + w.area_dram0_1_wr_ena().bit(writes) + }); + + regs.intr_clr().write(|w| { + w.area_dram0_1_rd_clr().set_bit(); + w.area_dram0_1_wr_clr().set_bit() + }); + + regs.intr_ena().modify(|_, w| { + w.area_dram0_1_rd_intr_ena().set_bit(); + w.area_dram0_1_wr_intr_ena().set_bit() + }); + } + + fn internal_disable_region1_monitor(&mut self, cpu: usize) { + let regs = self.regs().cpu(cpu); + + regs.intr_ena().modify(|_, w| { + w.area_dram0_1_rd_intr_ena().clear_bit(); + w.area_dram0_1_wr_intr_ena().clear_bit() + }); + + regs.montr_ena().modify(|_, w| { + w.area_dram0_1_rd_ena().clear_bit(); + w.area_dram0_1_wr_ena().clear_bit() + }); + } + + fn internal_clear_region1_monitor_interrupt(&mut self, cpu: usize) { + self.regs().cpu(cpu).intr_clr().write(|w| { + w.area_dram0_1_rd_clr().set_bit(); + w.area_dram0_1_wr_clr().set_bit() + }); + } + + fn internal_is_region1_monitor_interrupt_set(&self, cpu: usize) -> bool { + let regs = self.regs().cpu(cpu); + let intrs = regs.intr_raw().read(); + + intrs.area_dram0_1_rd_raw().bit_is_set() || intrs.area_dram0_1_wr_raw().bit_is_set() + } + + fn internal_region_monitor_pc(&self, cpu: usize) -> u32 { + self.regs().cpu(cpu).area_pc().read().area_pc().bits() + } + + /// Enable region monitoring of read/write performed by the main CPU in a + /// certain memory region0. Whenever the bus reads or writes in the + /// specified memory region, an interrupt will be triggered. Two memory + /// regions (region0, region1) can be monitored at the same time. + pub fn enable_region0_monitor( + &mut self, + lower_bound: u32, + upper_bound: u32, + reads: bool, + writes: bool, + ) { + self.internal_enable_region0_monitor(0, lower_bound, upper_bound, reads, writes) + } + + /// Disable region0 monitoring on main core. + pub fn disable_region0_monitor(&mut self) { + self.internal_disable_region0_monitor(0) + } + /// Clear region0 monitoring interrupt on main core. pub fn clear_region0_monitor_interrupt(&mut self) { - self.regs().core_0_intr_clr().write(|w| { - w.core_0_area_dram0_0_rd_clr() - .set_bit() - .core_0_area_dram0_0_wr_clr() - .set_bit() - }); + self.internal_clear_region0_monitor_interrupt(0) } /// Check, if region0 monitoring interrupt is set on main core. pub fn is_region0_monitor_interrupt_set(&self) -> bool { - self.regs() - .core_0_intr_raw() - .read() - .core_0_area_dram0_0_rd_raw() - .bit_is_set() - || self - .regs() - .core_0_intr_raw() - .read() - .core_0_area_dram0_0_wr_raw() - .bit_is_set() + self.internal_is_region0_monitor_interrupt_set(0) } /// Enable region monitoring of read/write performed by the main CPU in a @@ -321,76 +358,27 @@ impl DebugAssist<'_> { reads: bool, writes: bool, ) { - self.regs() - .core_0_area_dram0_1_min() - .write(|w| unsafe { w.core_0_area_dram0_1_min().bits(lower_bound) }); - - self.regs() - .core_0_area_dram0_1_max() - .write(|w| unsafe { w.core_0_area_dram0_1_max().bits(upper_bound) }); - - self.regs().core_0_montr_ena().modify(|_, w| { - w.core_0_area_dram0_1_rd_ena() - .bit(reads) - .core_0_area_dram0_1_wr_ena() - .bit(writes) - }); - - self.clear_region1_monitor_interrupt(); - - self.regs().core_0_intr_ena().modify(|_, w| { - w.core_0_area_dram0_1_rd_intr_ena() - .set_bit() - .core_0_area_dram0_1_wr_intr_ena() - .set_bit() - }); + self.internal_enable_region1_monitor(0, lower_bound, upper_bound, reads, writes) } /// Disable region1 monitoring on main core. pub fn disable_region1_monitor(&mut self) { - self.regs().core_0_intr_ena().modify(|_, w| { - w.core_0_area_dram0_1_rd_intr_ena() - .clear_bit() - .core_0_area_dram0_1_wr_intr_ena() - .clear_bit() - }); - - self.regs().core_0_montr_ena().modify(|_, w| { - w.core_0_area_dram0_1_rd_ena() - .clear_bit() - .core_0_area_dram0_1_wr_ena() - .clear_bit() - }); + self.internal_disable_region1_monitor(0) } /// Clear region1 monitoring interrupt on main core. pub fn clear_region1_monitor_interrupt(&mut self) { - self.regs().core_0_intr_clr().write(|w| { - w.core_0_area_dram0_1_rd_clr() - .set_bit() - .core_0_area_dram0_1_wr_clr() - .set_bit() - }); + self.internal_clear_region1_monitor_interrupt(0) } /// Check, if region1 monitoring interrupt is set on main core. pub fn is_region1_monitor_interrupt_set(&self) -> bool { - self.regs() - .core_0_intr_raw() - .read() - .core_0_area_dram0_1_rd_raw() - .bit_is_set() - || self - .regs() - .core_0_intr_raw() - .read() - .core_0_area_dram0_1_wr_raw() - .bit_is_set() + self.internal_is_region1_monitor_interrupt_set(0) } /// Get region monitoring PC value on main core. pub fn region_monitor_pc(&self) -> u32 { - self.regs().core_0_area_pc().read().core_0_area_pc().bits() + self.internal_region_monitor_pc(0) } } @@ -406,71 +394,22 @@ impl DebugAssist<'_> { reads: bool, writes: bool, ) { - self.regs() - .core_1_area_dram0_0_min() - .write(|w| unsafe { w.core_1_area_dram0_0_min().bits(lower_bound) }); - - self.regs() - .core_1_area_dram0_0_max() - .write(|w| unsafe { w.core_1_area_dram0_0_max().bits(upper_bound) }); - - self.regs().core_1_montr_ena().modify(|_, w| { - w.core_1_area_dram0_0_rd_ena() - .bit(reads) - .core_1_area_dram0_0_wr_ena() - .bit(writes) - }); - - self.clear_core1_region0_monitor_interrupt(); - - self.regs().core_1_intr_ena().modify(|_, w| { - w.core_1_area_dram0_0_rd_intr_ena() - .set_bit() - .core_1_area_dram0_0_wr_intr_ena() - .set_bit() - }); + self.internal_enable_region0_monitor(1, lower_bound, upper_bound, reads, writes) } /// Disable region0 monitoring on secondary core. pub fn disable_core1_region0_monitor(&mut self) { - self.regs().core_1_intr_ena().modify(|_, w| { - w.core_1_area_dram0_0_rd_intr_ena() - .clear_bit() - .core_1_area_dram0_0_wr_intr_ena() - .clear_bit() - }); - - self.regs().core_1_montr_ena().modify(|_, w| { - w.core_1_area_dram0_0_rd_ena() - .clear_bit() - .core_1_area_dram0_0_wr_ena() - .clear_bit() - }); + self.internal_disable_region0_monitor(1) } /// Clear region0 monitoring interrupt on secondary core. pub fn clear_core1_region0_monitor_interrupt(&mut self) { - self.regs().core_1_intr_clr().write(|w| { - w.core_1_area_dram0_0_rd_clr() - .set_bit() - .core_1_area_dram0_0_wr_clr() - .set_bit() - }); + self.internal_clear_region0_monitor_interrupt(1) } /// Check, if region0 monitoring interrupt is set on secondary core. pub fn is_core1_region0_monitor_interrupt_set(&self) -> bool { - self.regs() - .core_1_intr_raw() - .read() - .core_1_area_dram0_0_rd_raw() - .bit_is_set() - || self - .regs() - .core_1_intr_raw() - .read() - .core_1_area_dram0_0_wr_raw() - .bit_is_set() + self.internal_is_region0_monitor_interrupt_set(1) } /// Enable region monitoring of read/write performed by the secondary CPU in @@ -483,75 +422,26 @@ impl DebugAssist<'_> { reads: bool, writes: bool, ) { - self.regs() - .core_1_area_dram0_1_min() - .write(|w| unsafe { w.core_1_area_dram0_1_min().bits(lower_bound) }); - - self.regs() - .core_1_area_dram0_1_max() - .write(|w| unsafe { w.core_1_area_dram0_1_max().bits(upper_bound) }); - - self.regs().core_1_montr_ena().modify(|_, w| { - w.core_1_area_dram0_1_rd_ena() - .bit(reads) - .core_1_area_dram0_1_wr_ena() - .bit(writes) - }); - - self.clear_core1_region1_monitor_interrupt(); - - self.regs().core_1_intr_ena().modify(|_, w| { - w.core_1_area_dram0_1_rd_intr_ena() - .set_bit() - .core_1_area_dram0_1_wr_intr_ena() - .set_bit() - }); + self.internal_enable_region1_monitor(1, lower_bound, upper_bound, reads, writes) } /// Disable region1 monitoring on secondary core. pub fn disable_core1_region1_monitor(&mut self) { - self.regs().core_1_intr_ena().modify(|_, w| { - w.core_1_area_dram0_1_rd_intr_ena() - .clear_bit() - .core_1_area_dram0_1_wr_intr_ena() - .clear_bit() - }); - - self.regs().core_1_montr_ena().modify(|_, w| { - w.core_1_area_dram0_1_rd_ena() - .clear_bit() - .core_1_area_dram0_1_wr_ena() - .clear_bit() - }); + self.internal_disable_region1_monitor(1) } /// Clear region1 monitoring interrupt on secondary core. pub fn clear_core1_region1_monitor_interrupt(&mut self) { - self.regs().core_1_intr_clr().write(|w| { - w.core_1_area_dram0_1_rd_clr() - .set_bit() - .core_1_area_dram0_1_wr_clr() - .set_bit() - }); + self.internal_clear_region1_monitor_interrupt(1) } /// Check, if region1 monitoring interrupt is set on secondary core. pub fn is_core1_region1_monitor_interrupt_set(&self) -> bool { - self.regs() - .core_1_intr_raw() - .read() - .core_1_area_dram0_1_rd_raw() - .bit_is_set() - || self - .regs() - .core_1_intr_raw() - .read() - .core_1_area_dram0_1_wr_raw() - .bit_is_set() + self.internal_is_region1_monitor_interrupt_set(1) } /// Get region monitoring PC value on secondary core. pub fn core1_region_monitor_pc(&self) -> u32 { - self.regs().core_1_area_pc().read().core_1_area_pc().bits() + self.internal_region_monitor_pc(1) } } diff --git a/esp-hal/src/clock/clocks_ll/esp32.rs b/esp-hal/src/clock/clocks_ll/esp32.rs index 4b57900efc2..f23f56e39bd 100644 --- a/esp-hal/src/clock/clocks_ll/esp32.rs +++ b/esp-hal/src/clock/clocks_ll/esp32.rs @@ -162,7 +162,7 @@ pub(crate) fn esp32_rtc_update_to_xtal(freq: XtalClock, _div: u32) { .modify(|_, w| w.soc_clk_sel().xtal()); LPWR::regs() .store5() - .modify(|_, w| unsafe { w.scratch5().bits(value) }); + .modify(|_, w| unsafe { w.data().bits(value) }); // lower the voltage LPWR::regs() @@ -199,7 +199,7 @@ pub(crate) fn set_cpu_freq(cpu_freq_mhz: crate::clock::CpuClock) { LPWR::regs().clk_conf().modify(|_, w| w.soc_clk_sel().pll()); LPWR::regs() .store5() - .modify(|_, w| unsafe { w.scratch5().bits(value) }); + .modify(|_, w| unsafe { w.data().bits(value) }); esp32_update_cpu_freq(cpu_freq_mhz.mhz()); } diff --git a/esp-hal/src/clock/clocks_ll/esp32c2.rs b/esp-hal/src/clock/clocks_ll/esp32c2.rs index 4f83dde5021..63ebc934c1a 100644 --- a/esp-hal/src/clock/clocks_ll/esp32c2.rs +++ b/esp-hal/src/clock/clocks_ll/esp32c2.rs @@ -127,7 +127,7 @@ pub(crate) fn esp32c2_rtc_apb_freq_update(apb_freq: ApbClock) { LPWR::regs() .store5() - .modify(|_, w| unsafe { w.scratch5().bits(value) }); + .modify(|_, w| unsafe { w.data().bits(value) }); } // Mask for clock bits used by both WIFI and Bluetooth, 0, 1, 2, 3, 7, 8, 9, 10, diff --git a/esp-hal/src/clock/clocks_ll/esp32c3.rs b/esp-hal/src/clock/clocks_ll/esp32c3.rs index 94c3de26edb..564775b2ed2 100644 --- a/esp-hal/src/clock/clocks_ll/esp32c3.rs +++ b/esp-hal/src/clock/clocks_ll/esp32c3.rs @@ -161,7 +161,7 @@ pub(crate) fn esp32c3_rtc_apb_freq_update(apb_freq: ApbClock) { LPWR::regs() .store5() - .modify(|_, w| unsafe { w.scratch5().bits(value) }); + .modify(|_, w| unsafe { w.data().bits(value) }); } // Mask for clock bits used by both WIFI and Bluetooth, 0, 1, 2, 3, 7, 8, 9, 10, diff --git a/esp-hal/src/clock/clocks_ll/esp32c6.rs b/esp-hal/src/clock/clocks_ll/esp32c6.rs index b4d9082719c..a657e80bee0 100644 --- a/esp-hal/src/clock/clocks_ll/esp32c6.rs +++ b/esp-hal/src/clock/clocks_ll/esp32c6.rs @@ -141,7 +141,7 @@ pub(crate) fn esp32c6_rtc_apb_freq_update(apb_freq: ApbClock) { LP_AON::regs() .store5() - .modify(|_, w| unsafe { w.lp_aon_store5().bits(value) }); + .modify(|_, w| unsafe { w.data().bits(value) }); } fn clk_ll_mspi_fast_set_hs_divider(divider: u32) { diff --git a/esp-hal/src/clock/clocks_ll/esp32h2.rs b/esp-hal/src/clock/clocks_ll/esp32h2.rs index d2a095c5ea7..fd312e5ec4c 100644 --- a/esp-hal/src/clock/clocks_ll/esp32h2.rs +++ b/esp-hal/src/clock/clocks_ll/esp32h2.rs @@ -161,7 +161,7 @@ pub(crate) fn esp32h2_rtc_apb_freq_update(apb_freq: ApbClock) { LP_AON::regs() .store5() - .modify(|_, w| unsafe { w.lp_aon_store5().bits(value) }); + .modify(|_, w| unsafe { w.data().bits(value) }); } fn clk_ll_cpu_set_divider(divider: u32) { diff --git a/esp-hal/src/clock/clocks_ll/esp32s2.rs b/esp-hal/src/clock/clocks_ll/esp32s2.rs index ca5909b29e0..f6ec8ee722d 100644 --- a/esp-hal/src/clock/clocks_ll/esp32s2.rs +++ b/esp-hal/src/clock/clocks_ll/esp32s2.rs @@ -38,7 +38,7 @@ pub(crate) fn set_cpu_clock(cpu_clock_speed: CpuClock) { let value = (((80 * MHZ) >> 12) & UINT16_MAX) | ((((80 * MHZ) >> 12) & UINT16_MAX) << 16); LPWR::regs() .store5() - .modify(|_, w| unsafe { w.scratch5().bits(value) }); + .modify(|_, w| unsafe { w.data().bits(value) }); } // Mask for clock bits used by both WIFI and Bluetooth, bit 0, 3, 6, 7, 8, 9 diff --git a/esp-hal/src/clock/mod.rs b/esp-hal/src/clock/mod.rs index 9a94c5847b1..1f723e7cb6d 100644 --- a/esp-hal/src/clock/mod.rs +++ b/esp-hal/src/clock/mod.rs @@ -43,6 +43,7 @@ //! let peripherals = esp_hal::init(config); //! # {after_snippet} //! ``` +#![cfg_attr(not(feature = "rt"), expect(unused))] use core::{cell::Cell, marker::PhantomData}; diff --git a/esp-hal/src/debugger.rs b/esp-hal/src/debugger.rs index 2cb11eada5c..9a716e75ea1 100644 --- a/esp-hal/src/debugger.rs +++ b/esp-hal/src/debugger.rs @@ -10,9 +10,10 @@ pub fn debugger_connected() -> bool { #[cfg(riscv)] { crate::peripherals::ASSIST_DEBUG::regs() - .core_0_debug_mode() + .cpu(0) + .debug_mode() .read() - .core_0_debug_module_active() + .debug_module_active() .bit_is_set() } diff --git a/esp-hal/src/dma/buffers.rs b/esp-hal/src/dma/buffers.rs index e0817818cb9..5cbe4674970 100644 --- a/esp-hal/src/dma/buffers.rs +++ b/esp-hal/src/dma/buffers.rs @@ -1414,9 +1414,8 @@ unsafe impl DmaTxBuffer for EmptyBuf { type View = EmptyBuf; fn prepare(&mut self) -> Preparation { - #[allow(unused_unsafe)] // stable requires unsafe, nightly complains about it Preparation { - start: unsafe { core::ptr::addr_of_mut!(EMPTY).cast() }, + start: core::ptr::addr_of_mut!(EMPTY).cast(), direction: TransferDirection::Out, #[cfg(psram_dma)] accesses_psram: false, @@ -1444,9 +1443,8 @@ unsafe impl DmaRxBuffer for EmptyBuf { type View = EmptyBuf; fn prepare(&mut self) -> Preparation { - #[allow(unused_unsafe)] // stable requires unsafe, nightly complains about it Preparation { - start: unsafe { core::ptr::addr_of_mut!(EMPTY).cast() }, + start: core::ptr::addr_of_mut!(EMPTY).cast(), direction: TransferDirection::In, #[cfg(psram_dma)] accesses_psram: false, diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index b88ae5a1345..2f4b02d6f1a 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -987,7 +987,6 @@ impl DescriptorChain { self.descriptors.last().unwrap() } - #[allow(clippy::not_unsafe_ptr_arg_deref)] pub fn fill_for_rx( &mut self, circular: bool, @@ -1000,7 +999,6 @@ impl DescriptorChain { }) } - #[allow(clippy::not_unsafe_ptr_arg_deref)] pub fn fill_for_tx( &mut self, is_circular: bool, @@ -1690,7 +1688,6 @@ impl DmaChannelConvert for DEG { /// let spi_dma = configures_spi_dma(spi, dma_channel); /// # {after_snippet} /// ``` -#[allow(private_bounds)] pub trait DmaChannelFor: DmaChannel + DmaChannelConvert> { @@ -1709,7 +1706,6 @@ where /// /// You can use this in places where a peripheral driver would expect a /// `DmaRxChannel` implementation. -#[allow(private_bounds)] pub trait RxChannelFor: DmaChannelConvert> {} impl RxChannelFor

for RX where @@ -1725,7 +1721,6 @@ where /// /// You can use this in places where a peripheral driver would expect a /// `DmaTxChannel` implementation. -#[allow(private_bounds)] pub trait TxChannelFor: DmaChannelConvert> {} impl TxChannelFor

for TX where diff --git a/esp-hal/src/dma/pdma/copy.rs b/esp-hal/src/dma/pdma/copy.rs index 1f382606221..92be318801a 100644 --- a/esp-hal/src/dma/pdma/copy.rs +++ b/esp-hal/src/dma/pdma/copy.rs @@ -420,10 +420,9 @@ impl PdmaChannel for DMA_COPY<'_> { asynch::handle_in_interrupt::>(); asynch::handle_out_interrupt::>(); } - #[allow(non_upper_case_globals)] - pub(crate) static interrupt_handler: InterruptHandler = + pub(crate) static INTERRUPT_HANDLER: InterruptHandler = InterruptHandler::new(__esp_hal_internal_interrupt_handler, Priority::max()); - interrupt_handler + INTERRUPT_HANDLER } fn rx_async_flag(&self) -> &'static AtomicBool { static FLAG: AtomicBool = AtomicBool::new(false); diff --git a/esp-hal/src/dma/pdma/crypto.rs b/esp-hal/src/dma/pdma/crypto.rs index a6c802dcac0..805e8df8ece 100644 --- a/esp-hal/src/dma/pdma/crypto.rs +++ b/esp-hal/src/dma/pdma/crypto.rs @@ -476,10 +476,9 @@ impl PdmaChannel for DMA_CRYPTO<'_> { asynch::handle_in_interrupt::>(); asynch::handle_out_interrupt::>(); } - #[allow(non_upper_case_globals)] - pub(crate) static interrupt_handler: InterruptHandler = + pub(crate) static INTERRUPT_HANDLER: InterruptHandler = InterruptHandler::new(__esp_hal_internal_interrupt_handler, Priority::max()); - interrupt_handler + INTERRUPT_HANDLER } fn rx_async_flag(&self) -> &'static AtomicBool { static FLAG: AtomicBool = AtomicBool::new(false); diff --git a/esp-hal/src/ecc.rs b/esp-hal/src/ecc.rs index 37af7e6e45b..9be0689855a 100644 --- a/esp-hal/src/ecc.rs +++ b/esp-hal/src/ecc.rs @@ -436,7 +436,7 @@ impl Ecc<'_, Dm> { /// /// This function will return an error if the point is not on the selected /// elliptic curve. - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] #[cfg(esp32h2)] pub fn affine_point_verification_multiplication( &mut self, diff --git a/esp-hal/src/gpio/interrupt.rs b/esp-hal/src/gpio/interrupt.rs index 273153f4c91..99e604949cb 100644 --- a/esp-hal/src/gpio/interrupt.rs +++ b/esp-hal/src/gpio/interrupt.rs @@ -58,18 +58,17 @@ use portable_atomic::{AtomicPtr, Ordering}; use procmacros::ram; use strum::EnumCount; +#[cfg(feature = "rt")] +use crate::interrupt::{self, DEFAULT_INTERRUPT_HANDLER}; use crate::{ - gpio::{AnyPin, GpioBank, InputPin, set_int_enable}, - interrupt::{self, DEFAULT_INTERRUPT_HANDLER, Priority}, + gpio::{AnyPin, GPIO_LOCK, GpioBank, InputPin, set_int_enable}, + interrupt::Priority, peripherals::{GPIO, Interrupt}, - sync::RawMutex, }; /// Convenience constant for `Option::None` pin pub(super) static USER_INTERRUPT_HANDLER: CFnPtr = CFnPtr::new(); -pub(super) static GPIO_LOCK: RawMutex = RawMutex::new(); - pub(super) struct CFnPtr(AtomicPtr<()>); impl CFnPtr { pub const fn new() -> Self { @@ -88,6 +87,7 @@ impl CFnPtr { } } +#[cfg(feature = "rt")] pub(crate) fn bind_default_interrupt_handler() { // We first check if a handler is set in the vector table. if let Some(handler) = interrupt::bound_handler(Interrupt::GPIO) { @@ -140,6 +140,7 @@ pub(super) fn set_interrupt_priority(interrupt: Interrupt, priority: Priority) { /// status bits unchanged. This enables functions like `is_interrupt_set` to /// work correctly. #[ram] +#[cfg(feature = "rt")] extern "C" fn default_gpio_interrupt_handler() { GPIO_LOCK.lock(|| { let banks = interrupt_status(); diff --git a/esp-hal/src/gpio/mod.rs b/esp-hal/src/gpio/mod.rs index 829d111c877..486ba8f6e8c 100644 --- a/esp-hal/src/gpio/mod.rs +++ b/esp-hal/src/gpio/mod.rs @@ -68,11 +68,12 @@ crate::unstable_module! { mod asynch; mod embedded_hal_impls; pub(crate) mod interrupt; +use interrupt::*; + mod placeholder; use core::fmt::Display; -use interrupt::*; pub use placeholder::NoPin; use portable_atomic::AtomicU32; use strum::EnumCount; @@ -82,10 +83,13 @@ use crate::{ interrupt::{InterruptHandler, Priority}, peripherals::{GPIO, IO_MUX, Interrupt}, private::{self, Sealed}, + sync::RawMutex, }; define_io_mux_signals!(); +pub(crate) static GPIO_LOCK: RawMutex = RawMutex::new(); + /// Represents a pin-peripheral connection that, when dropped, disconnects the /// peripheral from the pin. /// diff --git a/esp-hal/src/i2c/master/mod.rs b/esp-hal/src/i2c/master/mod.rs index 8e538e1bdd7..b44115dc2d8 100644 --- a/esp-hal/src/i2c/master/mod.rs +++ b/esp-hal/src/i2c/master/mod.rs @@ -1376,7 +1376,8 @@ fn set_filter( } } -#[allow(clippy::too_many_arguments, unused)] +#[expect(clippy::too_many_arguments)] +#[allow(unused)] /// Configures the clock and timing parameters for the I2C peripheral. fn configure_clock( register_block: &RegisterBlock, diff --git a/esp-hal/src/i2s/master.rs b/esp-hal/src/i2s/master.rs index f729f2012c7..c90e67e24d5 100644 --- a/esp-hal/src/i2s/master.rs +++ b/esp-hal/src/i2s/master.rs @@ -330,7 +330,6 @@ where impl<'d> I2s<'d, Blocking> { /// Construct a new I2S peripheral driver instance for the first I2S /// peripheral - #[allow(clippy::too_many_arguments)] pub fn new( i2s: impl Instance + 'd, standard: Standard, diff --git a/esp-hal/src/i2s/parallel.rs b/esp-hal/src/i2s/parallel.rs index d9781f7aff4..1faba7ab552 100644 --- a/esp-hal/src/i2s/parallel.rs +++ b/esp-hal/src/i2s/parallel.rs @@ -134,7 +134,7 @@ pub struct TxSixteenBits<'d> { } impl<'d> TxSixteenBits<'d> { - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] /// Creates a new `TxSixteenBits` instance with the provided output pins. pub fn new( pin_0: impl PeripheralOutput<'d>, @@ -199,7 +199,7 @@ pub struct TxEightBits<'d> { } impl<'d> TxEightBits<'d> { - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] /// Creates a new `TxSEightBits` instance with the provided output pins. pub fn new( pin_0: impl PeripheralOutput<'d>, diff --git a/esp-hal/src/interrupt/mod.rs b/esp-hal/src/interrupt/mod.rs index 58db1aaae5d..77a6d19ffa1 100644 --- a/esp-hal/src/interrupt/mod.rs +++ b/esp-hal/src/interrupt/mod.rs @@ -84,14 +84,23 @@ mod xtensa; pub mod software; +#[cfg(feature = "rt")] #[unsafe(no_mangle)] -extern "C" fn EspDefaultHandler(_interrupt: crate::peripherals::Interrupt) { - panic!("Unhandled interrupt: {:?}", _interrupt); +extern "C" fn EspDefaultHandler() { + panic!("Unhandled interrupt"); } /// Default (unhandled) interrupt handler pub const DEFAULT_INTERRUPT_HANDLER: InterruptHandler = InterruptHandler::new( - unsafe { core::mem::transmute::<*const (), extern "C" fn()>(EspDefaultHandler as *const ()) }, + { + unsafe extern "C" { + fn EspDefaultHandler(); + } + + unsafe { + core::mem::transmute::(EspDefaultHandler) + } + }, Priority::min(), ); diff --git a/esp-hal/src/interrupt/riscv.rs b/esp-hal/src/interrupt/riscv.rs index c0f49d7063e..5b5d82d8956 100644 --- a/esp-hal/src/interrupt/riscv.rs +++ b/esp-hal/src/interrupt/riscv.rs @@ -12,7 +12,9 @@ //! interrupt15() => Priority::Priority15 //! ``` +#[cfg(feature = "rt")] pub use esp_riscv_rt::TrapFrame; +use procmacros::ram; use riscv::register::{mcause, mtvec}; #[cfg(not(plic))] @@ -204,59 +206,7 @@ impl TryFrom for Priority { /// The interrupts reserved by the HAL #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] -pub static RESERVED_INTERRUPTS: &[usize] = PRIORITY_TO_INTERRUPT; - -/// # Safety -/// -/// This function is called from an assembly trap handler. -#[doc(hidden)] -#[unsafe(link_section = ".trap.rust")] -#[unsafe(export_name = "_start_trap_rust_hal")] -pub unsafe extern "C" fn start_trap_rust_hal(trap_frame: *mut TrapFrame) { - assert!( - mcause::read().is_exception(), - "Arrived into _start_trap_rust_hal but mcause is not an exception!" - ); - unsafe extern "C" { - fn ExceptionHandler(tf: *mut TrapFrame); - } - unsafe { - ExceptionHandler(trap_frame); - } -} - -#[doc(hidden)] -#[unsafe(no_mangle)] -pub fn _setup_interrupts() { - unsafe extern "C" { - static _vector_table: *const u32; - } - - unsafe { - // 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::peripherals::Interrupt::try_from(peripheral_interrupt) - .map(|intr| { - #[cfg(multi_core)] - disable(Cpu::AppCpu, intr); - disable(Cpu::ProCpu, intr); - }) - .ok(); - } - - let vec_table = &_vector_table as *const _ as usize; - mtvec::write(vec_table, mtvec::TrapMode::Vectored); - - crate::interrupt::init_vectoring(); - }; - - #[cfg(plic)] - unsafe { - core::arch::asm!("csrw mie, {0}", in(reg) u32::MAX); - } -} +pub static RESERVED_INTERRUPTS: &[u32] = PRIORITY_TO_INTERRUPT; /// Enable an interrupt by directly binding it to a available CPU interrupt /// @@ -284,17 +234,8 @@ pub fn enable_direct( } /// Disable the given peripheral interrupt. -pub fn disable(_core: Cpu, interrupt: Interrupt) { - unsafe { - let interrupt_number = interrupt as isize; - let intr_map_base = crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32; - - // set to 0 to disable the peripheral interrupt on chips with an interrupt - // controller other than PLIC use the disabled interrupt 31 otherwise - intr_map_base - .offset(interrupt_number) - .write_volatile(DISABLED_CPU_INTERRUPT); - } +pub fn disable(core: Cpu, interrupt: Interrupt) { + map_raw(core, interrupt, DISABLED_CPU_INTERRUPT) } /// Get status of peripheral interrupts @@ -303,21 +244,21 @@ pub fn status(_core: Cpu) -> InterruptStatus { cfg_if::cfg_if! { if #[cfg(interrupts_status_registers = "3")] { InterruptStatus::from( - INTERRUPT_CORE0::regs().intr_status_reg_0().read().bits(), - INTERRUPT_CORE0::regs().intr_status_reg_1().read().bits(), - INTERRUPT_CORE0::regs().int_status_reg_2().read().bits(), + INTERRUPT_CORE0::regs().core_0_intr_status(0).read().bits(), + INTERRUPT_CORE0::regs().core_0_intr_status(1).read().bits(), + INTERRUPT_CORE0::regs().core_0_intr_status(2).read().bits(), ) } else if #[cfg(interrupts_status_registers = "4")] { InterruptStatus::from( - INTERRUPT_CORE0::regs().intr_status_reg_0().read().bits(), - INTERRUPT_CORE0::regs().intr_status_reg_1().read().bits(), - INTERRUPT_CORE0::regs().intr_status_reg_2().read().bits(), - INTERRUPT_CORE0::regs().intr_status_reg_3().read().bits(), + INTERRUPT_CORE0::regs().core_0_intr_status(0).read().bits(), + INTERRUPT_CORE0::regs().core_0_intr_status(1).read().bits(), + INTERRUPT_CORE0::regs().core_0_intr_status(2).read().bits(), + INTERRUPT_CORE0::regs().core_0_intr_status(3).read().bits(), ) } else { InterruptStatus::from( - INTERRUPT_CORE0::regs().intr_status_reg_0().read().bits(), - INTERRUPT_CORE0::regs().intr_status_reg_1().read().bits(), + INTERRUPT_CORE0::regs().core_0_intr_status(0).read().bits(), + INTERRUPT_CORE0::regs().core_0_intr_status(1).read().bits(), ) } } @@ -328,21 +269,25 @@ pub fn status(_core: Cpu) -> InterruptStatus { /// # Safety /// /// Do not use CPU interrupts in the [`RESERVED_INTERRUPTS`]. -pub unsafe fn map(_core: Cpu, interrupt: Interrupt, which: CpuInterrupt) { - let interrupt_number = interrupt as isize; - let cpu_interrupt_number = which as isize; - #[cfg(not(multi_core))] - let intr_map_base = crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32; - #[cfg(multi_core)] - let intr_map_base = match _core { - Cpu::ProCpu => crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32, - Cpu::AppCpu => crate::soc::registers::INTERRUPT_MAP_BASE_APP_CPU as *mut u32, - }; +pub unsafe fn map(core: Cpu, interrupt: Interrupt, which: CpuInterrupt) { + map_raw(core, interrupt, which as u32) +} - unsafe { - intr_map_base - .offset(interrupt_number) - .write_volatile(cpu_interrupt_number as u32 + EXTERNAL_INTERRUPT_OFFSET); +fn map_raw(core: Cpu, interrupt: Interrupt, cpu_interrupt_number: u32) { + let interrupt_number = interrupt as usize; + + match core { + Cpu::ProCpu => { + INTERRUPT_CORE0::regs() + .core_0_intr_map(interrupt_number) + .write(|w| unsafe { w.bits(cpu_interrupt_number) }); + } + #[cfg(multi_core)] + Cpu::AppCpu => { + INTERRUPT_CORE1::regs() + .core_1_intr_map(interrupt_number) + .write(|w| unsafe { w.bits(cpu_interrupt_number) }); + } } } @@ -354,9 +299,7 @@ unsafe fn assigned_cpu_interrupt(interrupt: Interrupt) -> Option { let cpu_intr = unsafe { intr_map_base.offset(interrupt_number).read_volatile() }; if cpu_intr > 0 && cpu_intr != DISABLED_CPU_INTERRUPT { - Some(unsafe { - core::mem::transmute::(cpu_intr - EXTERNAL_INTERRUPT_OFFSET) - }) + Some(unsafe { core::mem::transmute::(cpu_intr) }) } else { None } @@ -367,26 +310,21 @@ pub(crate) fn bound_cpu_interrupt_for(_cpu: Cpu, interrupt: Interrupt) -> Option } mod vectored { - use procmacros::ram; - use super::*; // Setup interrupts ready for vectoring #[doc(hidden)] pub(crate) unsafe fn init_vectoring() { - for (prio, num) in PRIORITY_TO_INTERRUPT.iter().enumerate() { + for (num, prio) in PRIORITY_TO_INTERRUPT.iter().copied().zip(1..) { + let which = unsafe { core::mem::transmute::(num) }; + set_kind(Cpu::current(), which, InterruptKind::Level); unsafe { - set_kind( - Cpu::current(), - core::mem::transmute::(*num as u32), - InterruptKind::Level, - ); set_priority( Cpu::current(), - core::mem::transmute::(*num as u32), - core::mem::transmute::((prio as u8) + 1), + which, + core::mem::transmute::(prio), ); - enable_cpu_interrupt(core::mem::transmute::(*num as u32)); + enable_cpu_interrupt(which); } } } @@ -394,7 +332,7 @@ mod vectored { /// Get the interrupts configured for the core at the given priority /// matching the given status #[inline] - fn configured_interrupts( + pub(crate) fn configured_interrupts( core: Cpu, status: InterruptStatus, priority: Priority, @@ -435,7 +373,7 @@ mod vectored { } unsafe { let cpu_interrupt = core::mem::transmute::( - PRIORITY_TO_INTERRUPT[(level as usize) - 1] as u32, + PRIORITY_TO_INTERRUPT[(level as usize) - 1], ); map(cpu, interrupt, cpu_interrupt); enable_cpu_interrupt(cpu_interrupt); @@ -467,120 +405,6 @@ mod vectored { Some(addr) } } - - #[unsafe(no_mangle)] - #[ram] - unsafe fn handle_interrupts(cpu_intr: CpuInterrupt, context: &mut TrapFrame) { - let core = Cpu::current(); - let status = status(core); - - // this has no effect on level interrupts, but the interrupt may be an edge one - // so we clear it anyway - clear(core, cpu_intr); - - let priority = INTERRUPT_TO_PRIORITY[cpu_intr as usize]; - let prio: Priority = unsafe { core::mem::transmute(priority) }; - let configured_interrupts = configured_interrupts(core, status, prio); - - for interrupt_nr in configured_interrupts.iterator() { - // Don't use `Interrupt::try_from`. It's slower and placed in flash - let interrupt: Interrupt = unsafe { core::mem::transmute(interrupt_nr as u16) }; - unsafe { - handle_interrupt(interrupt, context); - } - } - } - - #[inline(always)] - unsafe fn handle_interrupt(interrupt: Interrupt, save_frame: &mut TrapFrame) { - unsafe extern "C" { - // defined in each hal - fn EspDefaultHandler(interrupt: Interrupt); - } - - let handler = unsafe { pac::__EXTERNAL_INTERRUPTS[interrupt as usize]._handler }; - - if core::ptr::eq( - handler as *const _, - EspDefaultHandler as *const unsafe extern "C" fn(), - ) { - unsafe { EspDefaultHandler(interrupt) }; - } else { - let handler: fn(&mut TrapFrame) = unsafe { - core::mem::transmute::(handler) - }; - handler(save_frame); - } - } - - // The compiler generates quite unfortunate code for - // ```rust,ignore - // #[no_mangle] - // #[ram] - // unsafe fn interrupt1(context: &mut TrapFrame) { - // handle_interrupts(CpuInterrupt::Interrupt1, context) - // } - // ``` - // - // Resulting in - // ```asm,ignore - // interrupt1: - // add sp,sp,-16 - // sw ra,12(sp) - // sw s0,8(sp) - // add s0,sp,16 - // mv a1,a0 - // li a0,1 - // lw ra,12(sp) - // lw s0,8(sp) - // add sp,sp,16 - // auipc t1,0x0 - // jr handle_interrupts - // ``` - // - // We can do better manually - use Rust again once/if that changes - macro_rules! interrupt_handler { - ($num:literal) => { - core::arch::global_asm! { - concat!( - r#" - .section .rwtext, "ax" - .global interrupt"#,$num,r#" - - interrupt"#,$num,r#": - mv a1, a0 - li a0,"#,$num,r#" - j handle_interrupts - "# - ) - } - }; - } - - interrupt_handler!(1); - interrupt_handler!(2); - interrupt_handler!(3); - interrupt_handler!(4); - interrupt_handler!(5); - interrupt_handler!(6); - interrupt_handler!(7); - interrupt_handler!(8); - interrupt_handler!(9); - interrupt_handler!(10); - interrupt_handler!(11); - interrupt_handler!(12); - interrupt_handler!(13); - interrupt_handler!(14); - interrupt_handler!(15); - - #[cfg(plic)] - interrupt_handler!(16); - #[cfg(plic)] - interrupt_handler!(17); - #[cfg(plic)] - interrupt_handler!(18); - #[cfg(plic)] - interrupt_handler!(19); } #[cfg(not(plic))] @@ -592,16 +416,29 @@ mod classic { pub(super) static DISABLED_CPU_INTERRUPT: u32 = 0; #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] - pub(super) static EXTERNAL_INTERRUPT_OFFSET: u32 = 0; - - #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] - pub(super) static PRIORITY_TO_INTERRUPT: &[usize] = + pub(super) static PRIORITY_TO_INTERRUPT: &[u32] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; // First element is not used, just there to avoid a -1 in the interrupt handler. #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] - pub(super) static INTERRUPT_TO_PRIORITY: [u8; 16] = - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + pub(super) static INTERRUPT_TO_PRIORITY: [Priority; 16] = [ + Priority::None, + Priority::Priority1, + Priority::Priority2, + Priority::Priority3, + Priority::Priority4, + Priority::Priority5, + Priority::Priority6, + Priority::Priority7, + Priority::Priority8, + Priority::Priority9, + Priority::Priority10, + Priority::Priority11, + Priority::Priority12, + Priority::Priority13, + Priority::Priority14, + Priority::Priority15, + ]; /// Enable a CPU interrupt /// @@ -663,12 +500,12 @@ mod classic { /// Get interrupt priority #[inline] pub(super) fn priority_by_core(_core: Cpu, cpu_interrupt: CpuInterrupt) -> Priority { - unsafe { priority(cpu_interrupt) } + priority(cpu_interrupt) } /// Get interrupt priority - called by assembly code #[inline] - pub(super) unsafe extern "C" fn priority(cpu_interrupt: CpuInterrupt) -> Priority { + pub(super) fn priority(cpu_interrupt: CpuInterrupt) -> Priority { let intr = INTERRUPT_CORE0::regs(); unsafe { core::mem::transmute::( @@ -676,38 +513,6 @@ mod classic { ) } } - #[unsafe(no_mangle)] - #[unsafe(link_section = ".trap")] - pub(super) unsafe extern "C" fn _handle_priority() -> u32 { - use super::mcause; - // Both C6 and H2 have 5 bits of code. The riscv crate masks 31 bits, which then - // causes a bounds check to be present. - let interrupt_id: usize = mcause::read().bits() & 0x1f; - let intr = INTERRUPT_CORE0::regs(); - let interrupt_priority = unsafe { - intr.cpu_int_pri(0) - .as_ptr() - .add(interrupt_id) - .read_volatile() - }; - - let prev_interrupt_priority = intr.cpu_int_thresh().read().bits(); - if interrupt_priority < 15 { - // leave interrupts disabled if interrupt is of max priority. - intr.cpu_int_thresh() - .write(|w| unsafe { w.bits(interrupt_priority + 1) }); // set the prio threshold to 1 more than current interrupt prio - unsafe { riscv::interrupt::enable() }; - } - prev_interrupt_priority - } - #[unsafe(no_mangle)] - #[unsafe(link_section = ".trap")] - pub(super) unsafe extern "C" fn _restore_priority(stored_prio: u32) { - riscv::interrupt::disable(); - let intr = INTERRUPT_CORE0::regs(); - intr.cpu_int_thresh() - .write(|w| unsafe { w.bits(stored_prio) }); - } /// Get the current run level (the level below which interrupts are masked). pub fn current_runlevel() -> Priority { @@ -736,6 +541,45 @@ mod classic { prev_interrupt_priority } + + #[cfg(feature = "rt")] + mod rt { + use super::*; + + #[unsafe(link_section = ".trap")] + #[unsafe(no_mangle)] + pub(super) unsafe extern "C" fn _handle_priority() -> u32 { + // Both C6 and H2 have 5 bits of code. The riscv crate masks 31 bits, which then + // causes a bounds check to be present. + let interrupt_id: usize = riscv::register::mcause::read().bits() & 0x1f; + let intr = INTERRUPT_CORE0::regs(); + let interrupt_priority = intr.cpu_int_pri(interrupt_id).read().bits(); + + let prev_interrupt_priority = intr.cpu_int_thresh().read().bits(); + if interrupt_priority < 15 { + // leave interrupts disabled if interrupt is of max priority. + intr.cpu_int_thresh() + .write(|w| unsafe { w.bits(interrupt_priority + 1) }); // set the prio threshold to 1 more than current interrupt prio + unsafe { riscv::interrupt::enable() }; + } + prev_interrupt_priority + } + + #[unsafe(link_section = ".trap")] + #[unsafe(no_mangle)] + unsafe extern "C" fn _restore_priority(stored_prio: u32) { + riscv::interrupt::disable(); + let intr = INTERRUPT_CORE0::regs(); + intr.cpu_int_thresh() + .write(|w| unsafe { w.bits(stored_prio) }); + } + + /// Globally exported so assembly code can call it. + #[unsafe(no_mangle)] + unsafe extern "C" fn priority(cpu_interrupt: CpuInterrupt) -> Priority { + super::priority(cpu_interrupt) + } + } } #[cfg(plic)] @@ -746,20 +590,36 @@ mod plic { #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] pub(super) static DISABLED_CPU_INTERRUPT: u32 = 31; - #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] - pub(super) static EXTERNAL_INTERRUPT_OFFSET: u32 = 0; - // don't use interrupts reserved for CLIC (0,3,4,7) // for some reason also CPU interrupt 8 doesn't work by default since it's // disabled after reset - so don't use that, too #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] - pub(super) static PRIORITY_TO_INTERRUPT: &[usize] = + pub(super) static PRIORITY_TO_INTERRUPT: &[u32] = &[1, 2, 5, 6, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]; // First element is not used, just there to avoid a -1 in the interrupt handler. #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] - pub(super) static INTERRUPT_TO_PRIORITY: [u8; 20] = [ - 0, 1, 2, 0, 0, 3, 4, 0, 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + pub(super) static INTERRUPT_TO_PRIORITY: [Priority; 20] = [ + Priority::None, + Priority::Priority1, + Priority::Priority2, + Priority::None, + Priority::None, + Priority::Priority3, + Priority::Priority4, + Priority::None, + Priority::None, + Priority::Priority5, + Priority::Priority6, + Priority::Priority7, + Priority::Priority8, + Priority::Priority9, + Priority::Priority10, + Priority::Priority11, + Priority::Priority12, + Priority::Priority13, + Priority::Priority14, + Priority::Priority15, ]; /// Enable a CPU interrupt @@ -768,13 +628,11 @@ mod plic { /// /// Make sure there is an interrupt handler registered. pub unsafe fn enable_cpu_interrupt(which: CpuInterrupt) { - unsafe { - PLIC_MX::regs().mxint_enable().modify(|r, w| { - let old = r.cpu_mxint_enable().bits(); - let new = old | (1 << (which as isize)); - w.cpu_mxint_enable().bits(new) - }); - } + PLIC_MX::regs().mxint_enable().modify(|r, w| { + let old = r.cpu_mxint_enable().bits(); + let new = old | (1 << (which as isize)); + unsafe { w.cpu_mxint_enable().bits(new) } + }); } /// Set the interrupt kind (i.e. level or edge) of an CPU interrupt @@ -787,13 +645,11 @@ mod plic { InterruptKind::Edge => 1, }; - unsafe { - PLIC_MX::regs().mxint_type().modify(|r, w| { - let old = r.cpu_mxint_type().bits(); - let new = old & !(1 << (which as isize)) | (interrupt_type << (which as isize)); - w.cpu_mxint_type().bits(new) - }); - } + PLIC_MX::regs().mxint_type().modify(|r, w| { + let old = r.cpu_mxint_type().bits(); + let new = old & !(1 << (which as isize)) | (interrupt_type << (which as isize)); + unsafe { w.cpu_mxint_type().bits(new) } + }); } /// Set the priority level of an CPU interrupt @@ -803,37 +659,30 @@ mod plic { /// Great care must be taken when using this function; avoid changing the /// priority of interrupts 1 - 15. pub unsafe fn set_priority(_core: Cpu, which: CpuInterrupt, priority: Priority) { - unsafe { - PLIC_MX::regs() - .mxint_pri(which as usize) - .modify(|_, w| w.cpu_mxint_pri().bits(priority as u8)); - } + PLIC_MX::regs() + .mxint_pri(which as usize) + .modify(|_, w| unsafe { w.cpu_mxint_pri().bits(priority as u8) }); } /// Clear a CPU interrupt #[inline] pub fn clear(_core: Cpu, which: CpuInterrupt) { - unsafe { - PLIC_MX::regs().mxint_clear().modify(|r, w| { - let old = r.cpu_mxint_clear().bits(); - let new = old | (1 << (which as isize)); - w.cpu_mxint_clear().bits(new) - }); - } + PLIC_MX::regs().mxint_clear().modify(|r, w| { + let old = r.cpu_mxint_clear().bits(); + let new = old | (1 << (which as isize)); + unsafe { w.cpu_mxint_clear().bits(new) } + }); } - /// Get interrupt priority + /// Get interrupt priority for the CPU #[inline] - pub(super) unsafe extern "C" fn priority_by_core( - _core: Cpu, - cpu_interrupt: CpuInterrupt, - ) -> Priority { - unsafe { priority(cpu_interrupt) } + pub fn priority_by_core(_core: Cpu, cpu_interrupt: CpuInterrupt) -> Priority { + priority(cpu_interrupt) } - /// Get interrupt priority - called by assembly code #[inline] - pub(super) unsafe extern "C" fn priority(cpu_interrupt: CpuInterrupt) -> Priority { + /// Get interrupt priority. + pub fn priority(cpu_interrupt: CpuInterrupt) -> Priority { let prio = PLIC_MX::regs() .mxint_pri(cpu_interrupt as usize) .read() @@ -841,41 +690,6 @@ mod plic { .bits(); unsafe { core::mem::transmute::(prio) } } - #[unsafe(no_mangle)] - #[unsafe(link_section = ".trap")] - pub(super) unsafe extern "C" fn _handle_priority() -> u32 { - let interrupt_id: usize = super::mcause::read().code(); // MSB is whether its exception or interrupt. - let interrupt_priority = PLIC_MX::regs() - .mxint_pri(interrupt_id) - .read() - .cpu_mxint_pri() - .bits(); - - let prev_interrupt_priority = PLIC_MX::regs() - .mxint_thresh() - .read() - .cpu_mxint_thresh() - .bits(); - if interrupt_priority < 15 { - // leave interrupts disabled if interrupt is of max priority. - PLIC_MX::regs() - .mxint_thresh() - .write(|w| unsafe { w.cpu_mxint_thresh().bits(interrupt_priority + 1) }); - - unsafe { - riscv::interrupt::enable(); - } - } - prev_interrupt_priority as u32 - } - #[unsafe(no_mangle)] - #[unsafe(link_section = ".trap")] - pub(super) unsafe extern "C" fn _restore_priority(stored_prio: u32) { - riscv::interrupt::disable(); - PLIC_MX::regs() - .mxint_thresh() - .write(|w| unsafe { w.cpu_mxint_thresh().bits(stored_prio as u8) }); - } /// Get the current run level (the level below which interrupts are masked). pub fn current_runlevel() -> Priority { @@ -908,4 +722,202 @@ mod plic { prev_interrupt_priority } + + #[cfg(feature = "rt")] + mod rt { + use super::*; + /// Get interrupt priority - called by assembly code + #[unsafe(no_mangle)] + pub(super) unsafe extern "C" fn priority(cpu_interrupt: CpuInterrupt) -> Priority { + super::priority(cpu_interrupt) + } + + #[unsafe(no_mangle)] + #[unsafe(link_section = ".trap")] + pub(super) unsafe extern "C" fn _handle_priority() -> u32 { + let interrupt_id: usize = riscv::register::mcause::read().code(); // MSB is whether its exception or interrupt. + let interrupt_priority = PLIC_MX::regs() + .mxint_pri(interrupt_id) + .read() + .cpu_mxint_pri() + .bits(); + + let prev_interrupt_priority = PLIC_MX::regs() + .mxint_thresh() + .read() + .cpu_mxint_thresh() + .bits(); + if interrupt_priority < 15 { + // leave interrupts disabled if interrupt is of max priority. + PLIC_MX::regs() + .mxint_thresh() + .write(|w| unsafe { w.cpu_mxint_thresh().bits(interrupt_priority + 1) }); + + unsafe { + riscv::interrupt::enable(); + } + } + prev_interrupt_priority as u32 + } + + #[unsafe(no_mangle)] + #[unsafe(link_section = ".trap")] + pub(super) unsafe extern "C" fn _restore_priority(stored_prio: u32) { + riscv::interrupt::disable(); + PLIC_MX::regs() + .mxint_thresh() + .write(|w| unsafe { w.cpu_mxint_thresh().bits(stored_prio as u8) }); + } + } +} + +#[cfg(feature = "rt")] +mod rt { + use esp_riscv_rt::TrapFrame; + + use super::*; + + /// # Safety + /// + /// This function is called from an assembly trap handler. + #[doc(hidden)] + #[unsafe(link_section = ".trap.rust")] + #[unsafe(export_name = "_start_trap_rust_hal")] + unsafe extern "C" fn start_trap_rust_hal(trap_frame: *mut TrapFrame) { + assert!( + mcause::read().is_exception(), + "Arrived into _start_trap_rust_hal but mcause is not an exception!" + ); + unsafe extern "C" { + fn ExceptionHandler(tf: *mut TrapFrame); + } + unsafe { + ExceptionHandler(trap_frame); + } + } + + #[doc(hidden)] + #[unsafe(no_mangle)] + unsafe fn _setup_interrupts() { + unsafe extern "C" { + static _vector_table: u32; + } + + // 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::peripherals::Interrupt::try_from(peripheral_interrupt) + .map(|intr| { + #[cfg(multi_core)] + disable(Cpu::AppCpu, intr); + disable(Cpu::ProCpu, intr); + }) + .ok(); + } + + unsafe { + let vec_table = (&_vector_table as *const u32).addr(); + mtvec::write(vec_table, mtvec::TrapMode::Vectored); + + crate::interrupt::init_vectoring(); + }; + + #[cfg(plic)] + unsafe { + core::arch::asm!("csrw mie, {0}", in(reg) u32::MAX); + } + } + + #[unsafe(no_mangle)] + #[ram] + unsafe fn handle_interrupts(cpu_intr: CpuInterrupt, context: &mut TrapFrame) { + let core = Cpu::current(); + let status = status(core); + + // this has no effect on level interrupts, but the interrupt may be an edge one + // so we clear it anyway + clear(core, cpu_intr); + + let prio = INTERRUPT_TO_PRIORITY[cpu_intr as usize]; + let configured_interrupts = vectored::configured_interrupts(core, status, prio); + + for interrupt_nr in configured_interrupts.iterator() { + let handler = unsafe { pac::__EXTERNAL_INTERRUPTS[interrupt_nr as usize]._handler }; + + let handler: fn(&mut TrapFrame) = unsafe { + core::mem::transmute::(handler) + }; + handler(context); + } + } + + // The compiler generates quite unfortunate code for + // ```rust,ignore + // #[no_mangle] + // #[ram] + // unsafe fn interrupt1(context: &mut TrapFrame) { + // handle_interrupts(CpuInterrupt::Interrupt1, context) + // } + // ``` + // + // Resulting in + // ```asm,ignore + // interrupt1: + // add sp,sp,-16 + // sw ra,12(sp) + // sw s0,8(sp) + // add s0,sp,16 + // mv a1,a0 + // li a0,1 + // lw ra,12(sp) + // lw s0,8(sp) + // add sp,sp,16 + // auipc t1,0x0 + // jr handle_interrupts + // ``` + // + // We can do better manually - use Rust again once/if that changes + macro_rules! interrupt_handler { + ($num:literal) => { + core::arch::global_asm! { + concat!( + r#" + .section .rwtext, "ax" + .global interrupt"#,$num,r#" + + interrupt"#,$num,r#": + mv a1, a0 + li a0,"#,$num,r#" + j handle_interrupts + "# + ) + } + }; + } + + interrupt_handler!(1); + interrupt_handler!(2); + interrupt_handler!(3); + interrupt_handler!(4); + interrupt_handler!(5); + interrupt_handler!(6); + interrupt_handler!(7); + interrupt_handler!(8); + interrupt_handler!(9); + interrupt_handler!(10); + interrupt_handler!(11); + interrupt_handler!(12); + interrupt_handler!(13); + interrupt_handler!(14); + interrupt_handler!(15); + + #[cfg(plic)] + interrupt_handler!(16); + #[cfg(plic)] + interrupt_handler!(17); + #[cfg(plic)] + interrupt_handler!(18); + #[cfg(plic)] + interrupt_handler!(19); } diff --git a/esp-hal/src/interrupt/software.rs b/esp-hal/src/interrupt/software.rs index 97bf2f208cb..0f0435d7eae 100644 --- a/esp-hal/src/interrupt/software.rs +++ b/esp-hal/src/interrupt/software.rs @@ -110,21 +110,15 @@ impl SoftwareInterrupt<'_, NUM> { } } - match NUM { - 0 => system - .cpu_intr_from_cpu_0() - .write(|w| w.cpu_intr_from_cpu_0().set_bit()), - 1 => system - .cpu_intr_from_cpu_1() - .write(|w| w.cpu_intr_from_cpu_1().set_bit()), - 2 => system - .cpu_intr_from_cpu_2() - .write(|w| w.cpu_intr_from_cpu_2().set_bit()), - 3 => system - .cpu_intr_from_cpu_3() - .write(|w| w.cpu_intr_from_cpu_3().set_bit()), + let reg = match NUM { + 0 => system.cpu_intr_from_cpu(0), + 1 => system.cpu_intr_from_cpu(1), + 2 => system.cpu_intr_from_cpu(2), + 3 => system.cpu_intr_from_cpu(3), _ => unreachable!(), }; + + reg.write(|w| w.cpu_intr().set_bit()); } /// Resets this software-interrupt @@ -137,21 +131,15 @@ impl SoftwareInterrupt<'_, NUM> { } } - match NUM { - 0 => system - .cpu_intr_from_cpu_0() - .write(|w| w.cpu_intr_from_cpu_0().clear_bit()), - 1 => system - .cpu_intr_from_cpu_1() - .write(|w| w.cpu_intr_from_cpu_1().clear_bit()), - 2 => system - .cpu_intr_from_cpu_2() - .write(|w| w.cpu_intr_from_cpu_2().clear_bit()), - 3 => system - .cpu_intr_from_cpu_3() - .write(|w| w.cpu_intr_from_cpu_3().clear_bit()), + let reg = match NUM { + 0 => system.cpu_intr_from_cpu(0), + 1 => system.cpu_intr_from_cpu(1), + 2 => system.cpu_intr_from_cpu(2), + 3 => system.cpu_intr_from_cpu(3), _ => unreachable!(), }; + + reg.write(|w| w.cpu_intr().clear_bit()); } } diff --git a/esp-hal/src/interrupt/xtensa.rs b/esp-hal/src/interrupt/xtensa.rs index 6818bd689e5..16ca7db13fa 100644 --- a/esp-hal/src/interrupt/xtensa.rs +++ b/esp-hal/src/interrupt/xtensa.rs @@ -1,8 +1,10 @@ //! Interrupt handling +use procmacros::ram; use xtensa_lx::interrupt; #[cfg(esp32)] pub(crate) use xtensa_lx::interrupt::free; +#[cfg(feature = "rt")] use xtensa_lx_rt::exception::Context; pub use self::vectored::*; @@ -121,7 +123,7 @@ impl CpuInterrupt { /// The interrupts reserved by the HAL #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] -pub static RESERVED_INTERRUPTS: &[usize] = &[ +pub static RESERVED_INTERRUPTS: &[u32] = &[ CpuInterrupt::Interrupt1LevelPriority1 as _, CpuInterrupt::Interrupt19LevelPriority2 as _, CpuInterrupt::Interrupt23LevelPriority3 as _, @@ -172,31 +174,41 @@ pub fn enable_direct(interrupt: Interrupt, cpu_interrupt: CpuInterrupt) -> Resul /// # Safety /// /// Do not use CPU interrupts in the [`RESERVED_INTERRUPTS`]. -pub unsafe fn map(core: Cpu, interrupt: Interrupt, which: CpuInterrupt) { - let interrupt_number = interrupt as isize; - let cpu_interrupt_number = which as isize; - unsafe { - let intr_map_base = match core { - Cpu::ProCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map().as_ptr(), - #[cfg(multi_core)] - Cpu::AppCpu => (*core1_interrupt_peripheral()).app_mac_intr_map().as_ptr(), - }; - intr_map_base - .offset(interrupt_number) - .write_volatile(cpu_interrupt_number as u32); +pub unsafe fn map(cpu: Cpu, interrupt: Interrupt, which: CpuInterrupt) { + let interrupt_number = interrupt as usize; + let cpu_interrupt_number = which as u32; + match cpu { + Cpu::ProCpu => unsafe { + (*core0_interrupt_peripheral()) + .core_0_intr_map(interrupt_number) + .write(|w| w.bits(cpu_interrupt_number)); + }, + #[cfg(multi_core)] + Cpu::AppCpu => unsafe { + (*core1_interrupt_peripheral()) + .core_1_intr_map(interrupt_number) + .write(|w| w.bits(cpu_interrupt_number)); + }, } } /// Get cpu interrupt assigned to peripheral interrupt pub(crate) fn bound_cpu_interrupt_for(cpu: Cpu, interrupt: Interrupt) -> Option { - let interrupt_number = interrupt as isize; - - let intr_map_base = match cpu { - Cpu::ProCpu => unsafe { (*core0_interrupt_peripheral()).pro_mac_intr_map().as_ptr() }, + let cpu_intr = match cpu { + Cpu::ProCpu => unsafe { + (*core0_interrupt_peripheral()) + .core_0_intr_map(interrupt as usize) + .read() + .bits() + }, #[cfg(multi_core)] - Cpu::AppCpu => unsafe { (*core1_interrupt_peripheral()).app_mac_intr_map().as_ptr() }, + Cpu::AppCpu => unsafe { + (*core1_interrupt_peripheral()) + .core_1_intr_map(interrupt as usize) + .read() + .bits() + }, }; - let cpu_intr = unsafe { intr_map_base.offset(interrupt_number).read_volatile() }; let cpu_intr = CpuInterrupt::from_u32(cpu_intr)?; if cpu_intr.is_peripheral() { @@ -208,18 +220,7 @@ pub(crate) fn bound_cpu_interrupt_for(cpu: Cpu, interrupt: Interrupt) -> Option< /// Disable the given peripheral interrupt pub fn disable(core: Cpu, interrupt: Interrupt) { - unsafe { - let interrupt_number = interrupt as isize; - let intr_map_base = match core { - Cpu::ProCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map().as_ptr(), - #[cfg(multi_core)] - Cpu::AppCpu => (*core1_interrupt_peripheral()).app_mac_intr_map().as_ptr(), - }; - // To disable an interrupt, map it to a CPU peripheral interrupt - intr_map_base - .offset(interrupt_number) - .write_volatile(CpuInterrupt::Interrupt16Timer2Priority5 as _); - } + unsafe { map(core, interrupt, CpuInterrupt::Interrupt16Timer2Priority5) } } /// Clear the given CPU interrupt @@ -236,30 +237,30 @@ pub fn status(core: Cpu) -> InterruptStatus { match core { Cpu::ProCpu => InterruptStatus::from( (*core0_interrupt_peripheral()) - .pro_intr_status_0() + .core_0_intr_status(0) .read() .bits(), (*core0_interrupt_peripheral()) - .pro_intr_status_1() + .core_0_intr_status(1) .read() .bits(), (*core0_interrupt_peripheral()) - .pro_intr_status_2() + .core_0_intr_status(2) .read() .bits(), ), #[cfg(multi_core)] Cpu::AppCpu => InterruptStatus::from( (*core1_interrupt_peripheral()) - .app_intr_status_0() + .core_1_intr_status(0) .read() .bits(), (*core1_interrupt_peripheral()) - .app_intr_status_1() + .core_1_intr_status(1) .read() .bits(), (*core1_interrupt_peripheral()) - .app_intr_status_2() + .core_1_intr_status(2) .read() .bits(), ), @@ -274,38 +275,38 @@ pub fn status(core: Cpu) -> InterruptStatus { match core { Cpu::ProCpu => InterruptStatus::from( (*core0_interrupt_peripheral()) - .pro_intr_status_0() + .core_0_intr_status(0) .read() .bits(), (*core0_interrupt_peripheral()) - .pro_intr_status_1() + .core_0_intr_status(1) .read() .bits(), (*core0_interrupt_peripheral()) - .pro_intr_status_2() + .core_0_intr_status(2) .read() .bits(), (*core0_interrupt_peripheral()) - .pro_intr_status_3() + .core_0_intr_status(3) .read() .bits(), ), #[cfg(multi_core)] Cpu::AppCpu => InterruptStatus::from( (*core1_interrupt_peripheral()) - .app_intr_status_0() + .core_1_intr_status(0) .read() .bits(), (*core1_interrupt_peripheral()) - .app_intr_status_1() + .core_1_intr_status(1) .read() .bits(), (*core1_interrupt_peripheral()) - .app_intr_status_2() + .core_1_intr_status(2) .read() .bits(), (*core1_interrupt_peripheral()) - .app_intr_status_3() + .core_1_intr_status(3) .read() .bits(), ), @@ -368,8 +369,6 @@ pub(crate) unsafe fn change_current_runlevel(level: Priority) -> Priority { } mod vectored { - use procmacros::ram; - use super::*; /// Interrupt priority levels. @@ -468,12 +467,16 @@ mod vectored { /// Get the interrupts configured for the core #[inline(always)] - fn configured_interrupts(core: Cpu, status: InterruptStatus, level: u32) -> InterruptStatus { + pub(crate) fn configured_interrupts( + core: Cpu, + status: InterruptStatus, + level: u32, + ) -> InterruptStatus { unsafe { let intr_map_base = match core { - Cpu::ProCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map().as_ptr(), + Cpu::ProCpu => (*core0_interrupt_peripheral()).core_0_intr_map(0).as_ptr(), #[cfg(multi_core)] - Cpu::AppCpu => (*core1_interrupt_peripheral()).app_mac_intr_map().as_ptr(), + Cpu::AppCpu => (*core1_interrupt_peripheral()).core_1_intr_map(0).as_ptr(), }; let mut res = InterruptStatus::empty(); @@ -482,9 +485,8 @@ mod vectored { let i = interrupt_nr as isize; let cpu_interrupt = intr_map_base.offset(i).read_volatile(); // safety: cast is safe because of repr(u32) - let cpu_interrupt: CpuInterrupt = - core::mem::transmute::(cpu_interrupt); - let int_level = cpu_interrupt.level() as u8 as u32; + let cpu_interrupt = core::mem::transmute::(cpu_interrupt); + let int_level = cpu_interrupt.level() as u32; if int_level == level { res.set(interrupt_nr); @@ -567,7 +569,7 @@ mod vectored { // TODO use CpuInterrupt::LevelX.mask() // TODO make it const #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] - static CPU_INTERRUPT_LEVELS: [u32; 8] = [ + pub(crate) static CPU_INTERRUPT_LEVELS: [u32; 8] = [ 0b_0000_0000_0000_0000_0000_0000_0000_0000, // Dummy level 0 0b_0000_0000_0000_0110_0011_0111_1111_1111, // Level_1 0b_0000_0000_0011_1000_0000_0000_0000_0000, // Level 2 @@ -578,28 +580,79 @@ mod vectored { 0b_0000_0000_0000_0000_0100_0000_0000_0000, // Level 7 ]; #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] - static CPU_INTERRUPT_INTERNAL: u32 = 0b_0010_0000_0000_0001_1000_1000_1100_0000; + pub(crate) static CPU_INTERRUPT_INTERNAL: u32 = 0b_0010_0000_0000_0001_1000_1000_1100_0000; #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] - static CPU_INTERRUPT_EDGE: u32 = 0b_0111_0000_0100_0000_0000_1100_1000_0000; + pub(crate) static CPU_INTERRUPT_EDGE: u32 = 0b_0111_0000_0100_0000_0000_1100_1000_0000; - #[inline] - fn cpu_interrupt_nr_to_cpu_interrupt_handler( - number: u32, - ) -> Option { - use xtensa_lx_rt::*; - // we're fortunate that all esp variants use the same CPU interrupt layout - Some(match number { - 6 => Timer0, - 7 => Software0, - 11 => Profiling, - 14 => NMI, - 15 => Timer1, - 16 => Timer2, - 29 => Software1, - _ => return None, - }) + #[cfg(esp32)] + pub(crate) mod chip_specific { + use super::*; + #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] + pub static INTERRUPT_EDGE: InterruptStatus = InterruptStatus::from( + 0b0000_0000_0000_0000_0000_0000_0000_0000, + 0b1111_1100_0000_0000_0000_0000_0000_0000, + 0b0000_0000_0000_0000_0000_0000_0000_0011, + ); + #[inline] + pub fn interrupt_is_edge(interrupt: Interrupt) -> bool { + [ + Interrupt::TG0_T0_EDGE, + Interrupt::TG0_T1_EDGE, + Interrupt::TG0_WDT_EDGE, + Interrupt::TG0_LACT_EDGE, + Interrupt::TG1_T0_EDGE, + Interrupt::TG1_T1_EDGE, + Interrupt::TG1_WDT_EDGE, + Interrupt::TG1_LACT_EDGE, + ] + .contains(&interrupt) + } + } + + #[cfg(esp32s2)] + pub(crate) mod chip_specific { + use super::*; + #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] + pub static INTERRUPT_EDGE: InterruptStatus = InterruptStatus::from( + 0b0000_0000_0000_0000_0000_0000_0000_0000, + 0b1100_0000_0000_0000_0000_0000_0000_0000, + 0b0000_0000_0000_0000_0000_0011_1011_1111, + ); + #[inline] + pub fn interrupt_is_edge(interrupt: Interrupt) -> bool { + [ + Interrupt::TG0_T0_EDGE, + Interrupt::TG0_T1_EDGE, + Interrupt::TG0_WDT_EDGE, + Interrupt::TG0_LACT_EDGE, + Interrupt::TG1_T0_EDGE, + Interrupt::TG1_T1_EDGE, + Interrupt::TG1_WDT_EDGE, + Interrupt::TG1_LACT_EDGE, + Interrupt::SYSTIMER_TARGET0, + Interrupt::SYSTIMER_TARGET1, + Interrupt::SYSTIMER_TARGET2, + ] + .contains(&interrupt) + } } + #[cfg(esp32s3)] + pub(crate) mod chip_specific { + use super::*; + #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] + pub static INTERRUPT_EDGE: InterruptStatus = InterruptStatus::empty(); + #[inline] + pub fn interrupt_is_edge(_interrupt: Interrupt) -> bool { + false + } + } +} + +#[cfg(feature = "rt")] +mod rt { + use super::{vectored::*, *}; + #[unsafe(no_mangle)] #[ram] unsafe fn __level_1_interrupt(save_frame: &mut Context) { @@ -672,98 +725,34 @@ mod vectored { let configured_interrupts = configured_interrupts(core, status, LEVEL); for interrupt_nr in configured_interrupts.iterator() { - // Don't use `Interrupt::try_from`. It's slower and placed in flash - let interrupt: Interrupt = unsafe { core::mem::transmute(interrupt_nr as u16) }; - - unsafe extern "C" { - // defined in each hal - fn EspDefaultHandler(interrupt: Interrupt); - } - - let handler = unsafe { pac::__INTERRUPTS[interrupt as usize]._handler }; - if core::ptr::eq( - handler as *const _, - EspDefaultHandler as *const unsafe extern "C" fn(), - ) { - unsafe { EspDefaultHandler(interrupt) }; - } else { - let handler: fn(&mut Context) = unsafe { - core::mem::transmute::(handler) - }; - handler(save_frame); - } + let handler = unsafe { pac::__INTERRUPTS[interrupt_nr as usize]._handler }; + let handler: fn(&mut Context) = unsafe { + core::mem::transmute::(handler) + }; + handler(save_frame); } } } - #[cfg(esp32)] - mod chip_specific { - use super::*; - #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] - pub static INTERRUPT_EDGE: InterruptStatus = InterruptStatus::from( - 0b0000_0000_0000_0000_0000_0000_0000_0000, - 0b1111_1100_0000_0000_0000_0000_0000_0000, - 0b0000_0000_0000_0000_0000_0000_0000_0011, - ); - #[inline] - pub fn interrupt_is_edge(interrupt: Interrupt) -> bool { - [ - Interrupt::TG0_T0_EDGE, - Interrupt::TG0_T1_EDGE, - Interrupt::TG0_WDT_EDGE, - Interrupt::TG0_LACT_EDGE, - Interrupt::TG1_T0_EDGE, - Interrupt::TG1_T1_EDGE, - Interrupt::TG1_WDT_EDGE, - Interrupt::TG1_LACT_EDGE, - ] - .contains(&interrupt) - } - } - - #[cfg(esp32s2)] - mod chip_specific { - use super::*; - #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] - pub static INTERRUPT_EDGE: InterruptStatus = InterruptStatus::from( - 0b0000_0000_0000_0000_0000_0000_0000_0000, - 0b1100_0000_0000_0000_0000_0000_0000_0000, - 0b0000_0000_0000_0000_0000_0011_1011_1111, - ); - #[inline] - pub fn interrupt_is_edge(interrupt: Interrupt) -> bool { - [ - Interrupt::TG0_T0_EDGE, - Interrupt::TG0_T1_EDGE, - Interrupt::TG0_WDT_EDGE, - Interrupt::TG0_LACT_EDGE, - Interrupt::TG1_T0_EDGE, - Interrupt::TG1_T1_EDGE, - Interrupt::TG1_WDT_EDGE, - Interrupt::TG1_LACT_EDGE, - Interrupt::SYSTIMER_TARGET0, - Interrupt::SYSTIMER_TARGET1, - Interrupt::SYSTIMER_TARGET2, - ] - .contains(&interrupt) - } - } - - #[cfg(esp32s3)] - mod chip_specific { - use super::*; - #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))] - pub static INTERRUPT_EDGE: InterruptStatus = InterruptStatus::empty(); - #[inline] - pub fn interrupt_is_edge(_interrupt: Interrupt) -> bool { - false - } + #[inline] + pub(crate) fn cpu_interrupt_nr_to_cpu_interrupt_handler( + number: u32, + ) -> Option { + use xtensa_lx_rt::*; + // we're fortunate that all esp variants use the same CPU interrupt layout + Some(match number { + 6 => Timer0, + 7 => Software0, + 11 => Profiling, + 14 => NMI, + 15 => Timer1, + 16 => Timer2, + 29 => Software1, + _ => return None, + }) } -} - -mod raw { - use super::*; + // Raw handlers for CPU interrupts, assembly only. unsafe extern "C" { fn level4_interrupt(save_frame: &mut Context); fn level5_interrupt(save_frame: &mut Context); diff --git a/esp-hal/src/lcd_cam/lcd/i8080.rs b/esp-hal/src/lcd_cam/lcd/i8080.rs index 2940898d9e7..58ad7c793eb 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -621,7 +621,7 @@ pub struct TxEightBits<'d> { } impl<'d> TxEightBits<'d> { - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] /// Creates a new `TxEightBits` instance with the provided output pins. pub fn new( pin_0: impl PeripheralOutput<'d>, @@ -676,7 +676,7 @@ pub struct TxSixteenBits<'d> { } impl<'d> TxSixteenBits<'d> { - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] /// Creates a new `TxSixteenBits` instance with the provided output pins. pub fn new( pin_0: impl PeripheralOutput<'d>, diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index 3d276c3584d..3a661b4347e 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -160,6 +160,23 @@ //! //! You might want to consider using [`#[deny(clippy::mem_forget)`](https://rust-lang.github.io/rust-clippy/v0.0.212/index.html#mem_forget) in your project. //! +//! ## Library usage +//! +//! If you intend to write a library that uses esp-hal, you should import it as follows: +//! +//! ```toml +//! [dependencies] +//! esp-hal = { version = "1", default-features = false } } +//! ``` +//! +//! This ensures that the `rt` feature is not enabled, nor any chip features. The application that +//! uses your library will then be able to choose the chip feature it needs and enable `rt` such +//! that only the final user application calls [`init`]. +//! +//! If your library depends on `unstable` features, you *must* use the `requires-unstable` feature, +//! and *not* the unstable feature itself. Doing so, improves the quality of the error messages if a +//! user hasn't enabled the unstable feature of esp-hal. +//! //! [documentation]: https://docs.espressif.com/projects/rust/esp-hal/latest/ //! [examples]: https://github.com/esp-rs/esp-hal/tree/main/examples //! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/ @@ -192,13 +209,14 @@ use esp_rom_sys as _; metadata!("build_info", CHIP_NAME, chip!()); -#[cfg(riscv)] -#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] +#[cfg(all(riscv, feature = "rt"))] +#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", feature = "rt"))))] #[cfg_attr(not(feature = "unstable"), doc(hidden))] pub use esp_riscv_rt::{self, riscv}; pub(crate) use peripherals::pac; #[cfg(xtensa)] -#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] +#[cfg(all(xtensa, feature = "rt"))] +#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", feature = "rt"))))] #[cfg_attr(not(feature = "unstable"), doc(hidden))] pub use xtensa_lx_rt::{self, xtensa_lx}; @@ -236,6 +254,7 @@ pub mod uart; mod macros; +#[cfg(feature = "rt")] pub use procmacros::blocking_main as main; #[cfg(any(lp_core, ulp_riscv_core))] #[cfg(feature = "unstable")] @@ -356,6 +375,7 @@ unstable_driver! { /// State of the CPU saved when entering exception or interrupt #[instability::unstable] +#[cfg(feature = "rt")] #[allow(unused_imports)] pub mod trapframe { #[cfg(riscv)] @@ -548,18 +568,19 @@ pub mod __macro_implementation { #[instability::unstable] pub const fn assert_is_persistable() {} + #[cfg(feature = "rt")] #[cfg(riscv)] pub use esp_riscv_rt::entry as __entry; + #[cfg(feature = "rt")] #[cfg(xtensa)] pub use xtensa_lx_rt::entry as __entry; } +use crate::clock::CpuClock; #[cfg(feature = "unstable")] use crate::config::{WatchdogConfig, WatchdogStatus}; -use crate::{ - clock::{Clocks, CpuClock}, - peripherals::Peripherals, -}; +#[cfg(feature = "rt")] +use crate::{clock::Clocks, peripherals::Peripherals}; /// System configuration. /// @@ -603,6 +624,8 @@ pub struct Config { /// let peripherals = init(Config::default()); /// # {after_snippet} /// ``` +#[cfg_attr(docsrs, doc(cfg(feature = "rt")))] +#[cfg(feature = "rt")] pub fn init(config: Config) -> Peripherals { crate::soc::pre_init(); @@ -626,9 +649,8 @@ pub fn init(config: Config) -> Peripherals { match config.watchdog.rwdt() { WatchdogStatus::Enabled(duration) => { + rtc.rwdt.set_timeout(crate::rtc_cntl::RwdtStage::Stage0, duration); rtc.rwdt.enable(); - rtc.rwdt - .set_timeout(crate::rtc_cntl::RwdtStage::Stage0, duration); } WatchdogStatus::Disabled => { rtc.rwdt.disable(); @@ -639,8 +661,8 @@ pub fn init(config: Config) -> Peripherals { match config.watchdog.timg0() { WatchdogStatus::Enabled(duration) => { let mut timg0_wd = crate::timer::timg::Wdt::>::new(); - timg0_wd.enable(); timg0_wd.set_timeout(crate::timer::timg::MwdtStage::Stage0, duration); + timg0_wd.enable(); } WatchdogStatus::Disabled => { crate::timer::timg::Wdt::>::new().disable(); @@ -651,8 +673,8 @@ pub fn init(config: Config) -> Peripherals { match config.watchdog.timg1() { WatchdogStatus::Enabled(duration) => { let mut timg1_wd = crate::timer::timg::Wdt::>::new(); - timg1_wd.enable(); timg1_wd.set_timeout(crate::timer::timg::MwdtStage::Stage0, duration); + timg1_wd.enable(); } WatchdogStatus::Disabled => { crate::timer::timg::Wdt::>::new().disable(); diff --git a/esp-hal/src/macros.rs b/esp-hal/src/macros.rs index adafee7fa5b..47c9adf27ac 100644 --- a/esp-hal/src/macros.rs +++ b/esp-hal/src/macros.rs @@ -299,6 +299,7 @@ macro_rules! ignore { #[doc(hidden)] macro_rules! metadata { ($category:literal, $key:ident, $value:expr) => { + #[cfg(feature = "rt")] #[unsafe(link_section = concat!(".espressif.metadata"))] #[used] #[unsafe(export_name = concat!($category, ".", stringify!($key)))] @@ -314,3 +315,155 @@ macro_rules! metadata { }; }; } + +#[procmacros::doc_replace] +/// Extract fields from [`Peripherals`][crate::peripherals::Peripherals] into named groups. +/// +/// ## Example +/// +/// ```rust,no_run +/// # {before_snippet} +/// # +/// use esp_hal::assign_resources; +/// +/// assign_resources! { +/// Resources<'d> { +/// display: DisplayResources<'d> { +/// spi: SPI2, +/// sda: GPIO6, +/// sclk: GPIO7, +/// cs: GPIO8, +/// dc: GPIO9, +/// }, +/// axl: AccelerometerResources<'d> { +/// i2c: I2C0, +/// sda: GPIO12, +/// scl: GPIO13, +/// }, +/// } +/// } +/// +/// # struct Display<'d>(core::marker::PhantomData<&'d ()>); +/// fn init_display<'d>(r: DisplayResources<'d>) -> Display<'d> { +/// // use `r.spi`, `r.sda`, `r.sclk`, `r.cs`, `r.dc` +/// todo!() +/// } +/// +/// # struct Accelerometer<'d>(core::marker::PhantomData<&'d ()>); +/// fn init_accelerometer<'d>(r: AccelerometerResources<'d>) -> Accelerometer<'d> { +/// // use `r.i2c`, `r.sda`, `r.scl` +/// todo!() +/// } +/// +/// // let peripherals = esp_hal::init(...); +/// let resources = split_resources!(peripherals); +/// +/// let display = init_display(resources.display); +/// let axl = init_accelerometer(resources.axl); +/// +/// // Other fields (`peripherals.UART0`, ...) of the `peripherals` struct can still be accessed. +/// # {after_snippet} +/// ``` +// Based on https://crates.io/crates/assign-resources +#[macro_export] +#[cfg(feature = "unstable")] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] +macro_rules! assign_resources { + { + $(#[$struct_meta:meta])* + $vis:vis $struct_name:ident<$struct_lt:lifetime> { + $( + $(#[$group_meta:meta])* + $group_name:ident : $group_struct:ident<$group_lt:lifetime> { + $( + $(#[$resource_meta:meta])* + $resource_name:ident : $resource_field:ident + ),* + $(,)? + } + ),+ + $(,)? + } + } => { + // Group structs + $( + $(#[$group_meta])* + #[allow(missing_docs)] + $vis struct $group_struct<$group_lt> { + $( + $(#[$resource_meta])* + pub $resource_name: $crate::peripherals::$resource_field<$group_lt>, + )+ + } + + impl<$group_lt> $group_struct<$group_lt> { + /// Unsafely create an instance of the assigned peripherals out of thin air. + /// + /// # Safety + /// + /// You must ensure that you're only using one instance of the contained peripherals at a time. + pub unsafe fn steal() -> Self { + unsafe { + Self { + $($resource_name: $crate::peripherals::$resource_field::steal()),* + } + } + } + + /// Creates a new reference to the peripheral group with a shorter lifetime. + /// + /// Use this method if you would like to keep working with the peripherals after + /// you dropped the drivers that consume this. + pub fn reborrow(&mut self) -> $group_struct<'_> { + $group_struct { + $($resource_name: self.$resource_name.reborrow()),* + } + } + } + )+ + + // Outer struct + $(#[$struct_meta])* + /// Assigned resources. + $vis struct $struct_name<$struct_lt> { + $( pub $group_name: $group_struct<$struct_lt>, )+ + } + + impl<$struct_lt> $struct_name<$struct_lt> { + /// Unsafely create an instance of the assigned peripherals out of thin air. + /// + /// # Safety + /// + /// You must ensure that you're only using one instance of the contained peripherals at a time. + pub unsafe fn steal() -> Self { + unsafe { + Self { + $($group_name: $group_struct::steal()),* + } + } + } + + /// Creates a new reference to the assigned peripherals with a shorter lifetime. + /// + /// Use this method if you would like to keep working with the peripherals after + /// you dropped the drivers that consume this. + pub fn reborrow(&mut self) -> $struct_name<'_> { + $struct_name { + $($group_name: self.$group_name.reborrow()),* + } + } + } + + /// Extracts resources from the `Peripherals` struct. + #[macro_export] + macro_rules! split_resources { + ($peris:ident) => { + $struct_name { + $($group_name: $group_struct { + $($resource_name: $peris.$resource_field),* + }),* + } + } + } + }; +} diff --git a/esp-hal/src/peripherals.rs b/esp-hal/src/peripherals.rs index 059f45e4578..7ee6f288d57 100644 --- a/esp-hal/src/peripherals.rs +++ b/esp-hal/src/peripherals.rs @@ -190,6 +190,7 @@ for_each_peripheral! { impl Peripherals { /// Returns all the peripherals *once* #[inline] + #[cfg_attr(not(feature = "rt"), expect(dead_code))] pub(crate) fn take() -> Self { #[unsafe(no_mangle)] static mut _ESP_HAL_DEVICE_PERIPHERALS: bool = false; diff --git a/esp-hal/src/rtc_cntl/mod.rs b/esp-hal/src/rtc_cntl/mod.rs index 6ee080d4b70..fdd5ef96521 100644 --- a/esp-hal/src/rtc_cntl/mod.rs +++ b/esp-hal/src/rtc_cntl/mod.rs @@ -562,27 +562,25 @@ impl RtcClock { let rtc_cntl = LPWR::regs(); if clk_8m_en { + // clk_ll_rc_fast_enable rtc_cntl.clk_conf().modify(|_, w| w.enb_ck8m().clear_bit()); - unsafe { - rtc_cntl.timer1().modify(|_, w| w.ck8m_wait().bits(5)); - } + + rtc_cntl + .timer1() + .modify(|_, w| unsafe { w.ck8m_wait().bits(5) }); + crate::rom::ets_delay_us(50); } else { + // clk_ll_rc_fast_disable rtc_cntl.clk_conf().modify(|_, w| w.enb_ck8m().set_bit()); rtc_cntl .timer1() .modify(|_, w| unsafe { w.ck8m_wait().bits(20) }); } - if d256_en { - rtc_cntl - .clk_conf() - .modify(|_, w| w.enb_ck8m_div().clear_bit()); - } else { - rtc_cntl - .clk_conf() - .modify(|_, w| w.enb_ck8m_div().set_bit()); - } + rtc_cntl + .clk_conf() + .modify(|_, w| w.enb_ck8m_div().bit(!d256_en)); } pub(crate) fn read_xtal_freq_mhz() -> Option { @@ -726,12 +724,9 @@ impl RtcClock { // Prepare calibration timg0.rtccalicfg().modify(|_, w| unsafe { - w.rtc_cali_clk_sel() - .bits(cal_clk as u8) - .rtc_cali_start_cycling() - .clear_bit() - .rtc_cali_max() - .bits(slowclk_cycles as u16) + w.rtc_cali_clk_sel().bits(cal_clk as u8); + w.rtc_cali_start_cycling().clear_bit(); + w.rtc_cali_max().bits(slowclk_cycles as u16) }); // Figure out how long to wait for calibration to finish @@ -1027,20 +1022,13 @@ impl Rwdt { // Apply default settings for WDT unsafe { rtc_cntl.wdtconfig0().modify(|_, w| { - w.wdt_stg0() - .bits(RwdtStageAction::ResetSystem as u8) - .wdt_cpu_reset_length() - .bits(7) - .wdt_sys_reset_length() - .bits(7) - .wdt_stg1() - .bits(RwdtStageAction::Off as u8) - .wdt_stg2() - .bits(RwdtStageAction::Off as u8) - .wdt_stg3() - .bits(RwdtStageAction::Off as u8) - .wdt_en() - .set_bit() + w.wdt_stg0().bits(RwdtStageAction::ResetSystem as u8); + w.wdt_cpu_reset_length().bits(7); + w.wdt_sys_reset_length().bits(7); + w.wdt_stg1().bits(RwdtStageAction::Off as u8); + w.wdt_stg2().bits(RwdtStageAction::Off as u8); + w.wdt_stg3().bits(RwdtStageAction::Off as u8); + w.wdt_en().set_bit() }); } } @@ -1055,63 +1043,17 @@ impl Rwdt { let timeout_raw = (timeout.as_millis() * (RtcClock::cycles_to_1ms() as u64)) as u32; self.set_write_protection(false); - unsafe { - #[cfg(esp32)] - match stage { - RwdtStage::Stage0 => rtc_cntl - .wdtconfig1() - .modify(|_, w| w.wdt_stg0_hold().bits(timeout_raw)), - RwdtStage::Stage1 => rtc_cntl - .wdtconfig2() - .modify(|_, w| w.wdt_stg1_hold().bits(timeout_raw)), - RwdtStage::Stage2 => rtc_cntl - .wdtconfig3() - .modify(|_, w| w.wdt_stg2_hold().bits(timeout_raw)), - RwdtStage::Stage3 => rtc_cntl - .wdtconfig4() - .modify(|_, w| w.wdt_stg3_hold().bits(timeout_raw)), - }; - - #[cfg(any(esp32c6, esp32h2))] - match stage { - RwdtStage::Stage0 => rtc_cntl.config1().modify(|_, w| { - w.wdt_stg0_hold() - .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) - }), - RwdtStage::Stage1 => rtc_cntl.config2().modify(|_, w| { - w.wdt_stg1_hold() - .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) - }), - RwdtStage::Stage2 => rtc_cntl.config3().modify(|_, w| { - w.wdt_stg2_hold() - .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) - }), - RwdtStage::Stage3 => rtc_cntl.config4().modify(|_, w| { - w.wdt_stg3_hold() - .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) - }), - }; - - #[cfg(not(any(esp32, esp32c6, esp32h2)))] - match stage { - RwdtStage::Stage0 => rtc_cntl.wdtconfig1().modify(|_, w| { - w.wdt_stg0_hold() - .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) - }), - RwdtStage::Stage1 => rtc_cntl.wdtconfig2().modify(|_, w| { - w.wdt_stg1_hold() - .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) - }), - RwdtStage::Stage2 => rtc_cntl.wdtconfig3().modify(|_, w| { - w.wdt_stg2_hold() - .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) - }), - RwdtStage::Stage3 => rtc_cntl.wdtconfig4().modify(|_, w| { - w.wdt_stg3_hold() - .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) - }), - }; - } + let config_reg = match stage { + RwdtStage::Stage0 => rtc_cntl.wdtconfig1(), + RwdtStage::Stage1 => rtc_cntl.wdtconfig2(), + RwdtStage::Stage2 => rtc_cntl.wdtconfig3(), + RwdtStage::Stage3 => rtc_cntl.wdtconfig4(), + }; + + #[cfg(not(esp32))] + let timeout_raw = timeout_raw >> (1 + Efuse::rwdt_multiplier()); + + config_reg.modify(|_, w| unsafe { w.hold().bits(timeout_raw) }); self.set_write_protection(true); } @@ -1121,21 +1063,14 @@ impl Rwdt { let rtc_cntl = LP_WDT::regs(); self.set_write_protection(false); - - match stage { - RwdtStage::Stage0 => rtc_cntl - .wdtconfig0() - .modify(|_, w| unsafe { w.wdt_stg0().bits(action as u8) }), - RwdtStage::Stage1 => rtc_cntl - .wdtconfig0() - .modify(|_, w| unsafe { w.wdt_stg1().bits(action as u8) }), - RwdtStage::Stage2 => rtc_cntl - .wdtconfig0() - .modify(|_, w| unsafe { w.wdt_stg2().bits(action as u8) }), - RwdtStage::Stage3 => rtc_cntl - .wdtconfig0() - .modify(|_, w| unsafe { w.wdt_stg3().bits(action as u8) }), - }; + rtc_cntl.wdtconfig0().modify(|_, w| unsafe { + match stage { + RwdtStage::Stage0 => w.wdt_stg0().bits(action as u8), + RwdtStage::Stage1 => w.wdt_stg1().bits(action as u8), + RwdtStage::Stage2 => w.wdt_stg2().bits(action as u8), + RwdtStage::Stage3 => w.wdt_stg3().bits(action as u8), + } + }); self.set_write_protection(true); } diff --git a/esp-hal/src/rtc_cntl/sleep/esp32c6.rs b/esp-hal/src/rtc_cntl/sleep/esp32c6.rs index 26af30cebea..dfde0ada2d7 100644 --- a/esp-hal/src/rtc_cntl/sleep/esp32c6.rs +++ b/esp-hal/src/rtc_cntl/sleep/esp32c6.rs @@ -646,7 +646,7 @@ impl SleepTimeConfig { // Calibrate rtc slow clock // TODO: do an actual calibration instead of a read - let slowclk_period = unsafe { lp_aon().store1().read().lp_aon_store1().bits() }; + let slowclk_period = unsafe { lp_aon().store1().read().data().bits() }; // Calibrate rtc fast clock, only PMU supported chips sleep process is needed. const FAST_CLK_SRC_CAL_CYCLES: u32 = 2048; @@ -730,7 +730,7 @@ impl SleepTimeConfig { #[rustfmt::skip] // ASCII art // When the SOC wakeup (lp timer or GPIO wakeup) and Modem wakeup (Beacon wakeup) complete, // the soc wakeup will be delayed until the RF is turned on in Modem state. - // + // // modem wakeup TBTT, RF on by HW // | | // \|/ \|/ @@ -744,7 +744,7 @@ impl SleepTimeConfig { // | | // |<-- PMU guard time, also the maximum time for the SOC -->| // | wake-up delay | - // + // const CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP: bool = true; let (rf_on_protect_time_us, sync_time_us) = if CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP { diff --git a/esp-hal/src/soc/esp32/gpio.rs b/esp-hal/src/soc/esp32/gpio.rs index 264ca8ebc89..3c0d51a2449 100644 --- a/esp-hal/src/soc/esp32/gpio.rs +++ b/esp-hal/src/soc/esp32/gpio.rs @@ -29,12 +29,10 @@ //! `gpio` peripheral to access the appropriate registers. macro_rules! rtcio_analog { - ( - $pin_num:expr, $rtc_pin:expr, $pin_reg:expr, $prefix:pat, $hold:ident $(, $rue:literal)? - ) => { + ($pin_peri:ident, $rtc_pin:expr, $pin_reg:expr, $prefix:pat, $hold:ident) => { paste::paste! { #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] - impl $crate::gpio::RtcPin for $crate::peripherals::[]<'_> { + impl $crate::gpio::RtcPin for $crate::peripherals::$pin_peri<'_> { fn rtc_number(&self) -> u8 { $rtc_pin } @@ -58,25 +56,25 @@ macro_rules! rtcio_analog { } } - $( - // FIXME: replace with $(ignore($rue)) once stable - $crate::ignore!($rue); - - #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] - impl $crate::gpio::RtcPinWithResistors for $crate::peripherals::[]<'_> { - fn rtcio_pullup(&self, enable: bool) { - $crate::peripherals::RTC_IO::regs() - .$pin_reg.modify(|_, w| w.[< $prefix rue >]().bit(enable)); - } + for_each_gpio! { + // Implement RtcPinWithResistors if $pin_peri is an output pin + ($n:tt, $pin_peri $in_afs:tt $out_afs:tt ($input:tt [Output])) => { + #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] + impl $crate::gpio::RtcPinWithResistors for $crate::peripherals::$pin_peri<'_> { + fn rtcio_pullup(&self, enable: bool) { + $crate::peripherals::RTC_IO::regs() + .$pin_reg.modify(|_, w| w.[< $prefix rue >]().bit(enable)); + } - fn rtcio_pulldown(&self, enable: bool) { - $crate::peripherals::RTC_IO::regs() - .$pin_reg.modify(|_, w| w.[< $prefix rde >]().bit(enable)); + fn rtcio_pulldown(&self, enable: bool) { + $crate::peripherals::RTC_IO::regs() + .$pin_reg.modify(|_, w| w.[< $prefix rde >]().bit(enable)); + } } - } - )? + }; + } - impl $crate::peripherals::[]<'_> { + impl $crate::peripherals::$pin_peri<'_> { /// Configures the pin for analog mode. pub(crate) fn set_analog_impl(&self) { use $crate::gpio::RtcPin; @@ -97,13 +95,13 @@ macro_rules! rtcio_analog { // Select function "RTC function 1" (GPIO) for analog use unsafe { w.[<$prefix fun_sel>]().bits(0b00) }; - // Disable pull-up and pull-down resistors on the pin, if it has them - $( - // FIXME: replace with $(ignore($rue)) once stable - $crate::ignore!($rue); - w.[<$prefix rue>]().bit(false); - w.[<$prefix rde>]().bit(false); - )? + for_each_gpio! { + // Disable pull-up and pull-down resistors on the pin, if it has them + ($n:tt, $pin_peri $in_afs:tt $out_afs:tt ($input:tt [Output])) => { + w.[<$prefix rue>]().bit(false); + w.[<$prefix rde>]().bit(false); + }; + } w }); @@ -113,68 +111,93 @@ macro_rules! rtcio_analog { }; ( - $( ( $pin_num:expr, $rtc_pin:expr, $pin_reg:expr, $prefix:pat, $hold:ident $(, $rue:literal )? ) )+ + $( ( $pin_peri:ident, $rtc_pin:expr, $pin_reg:expr, $prefix:pat, $hold:ident $(, $rue:literal )? ) )+ ) => { $( - rtcio_analog!($pin_num, $rtc_pin, $pin_reg, $prefix, $hold $(, $rue )?); + rtcio_analog!($pin_peri, $rtc_pin, $pin_reg, $prefix, $hold $(, $rue )?); )+ + }; +} - pub(crate) fn errata36(pin: $crate::gpio::AnyPin<'_>, pull_up: bool, pull_down: bool) { - use $crate::gpio::{Pin, RtcPinWithResistors}; +#[rustfmt::skip] +macro_rules! touch_out_reg { + ($regs:expr, 0) => { $regs.sar_touch_out1() }; + ($regs:expr, 1) => { $regs.sar_touch_out1() }; + ($regs:expr, 2) => { $regs.sar_touch_out2() }; + ($regs:expr, 3) => { $regs.sar_touch_out2() }; + ($regs:expr, 4) => { $regs.sar_touch_out3() }; + ($regs:expr, 5) => { $regs.sar_touch_out3() }; + ($regs:expr, 6) => { $regs.sar_touch_out4() }; + ($regs:expr, 7) => { $regs.sar_touch_out4() }; + ($regs:expr, 8) => { $regs.sar_touch_out5() }; + ($regs:expr, 9) => { $regs.sar_touch_out5() }; +} - let has_pullups = match pin.number() { - $( - $( $pin_num => $rue, )? - )+ - _ => false, - }; +#[rustfmt::skip] +macro_rules! touch_thres_reg { + ($regs:expr, 0) => { $regs.sar_touch_thres1() }; + ($regs:expr, 1) => { $regs.sar_touch_thres1() }; + ($regs:expr, 2) => { $regs.sar_touch_thres2() }; + ($regs:expr, 3) => { $regs.sar_touch_thres2() }; + ($regs:expr, 4) => { $regs.sar_touch_thres3() }; + ($regs:expr, 5) => { $regs.sar_touch_thres3() }; + ($regs:expr, 6) => { $regs.sar_touch_thres4() }; + ($regs:expr, 7) => { $regs.sar_touch_thres4() }; + ($regs:expr, 8) => { $regs.sar_touch_thres5() }; + ($regs:expr, 9) => { $regs.sar_touch_thres5() }; +} - if has_pullups { - pin.rtcio_pullup(pull_up); - pin.rtcio_pulldown(pull_down); - } - } - }; +#[rustfmt::skip] +macro_rules! touch_pad_reg { + ($regs:expr, 0) => { $regs.touch_pad0() }; + ($regs:expr, 1) => { $regs.touch_pad1() }; + ($regs:expr, 2) => { $regs.touch_pad2() }; + ($regs:expr, 3) => { $regs.touch_pad3() }; + ($regs:expr, 4) => { $regs.touch_pad4() }; + ($regs:expr, 5) => { $regs.touch_pad5() }; + ($regs:expr, 6) => { $regs.touch_pad6() }; + ($regs:expr, 7) => { $regs.touch_pad7() }; + ($regs:expr, 8) => { $regs.touch_pad8() }; + ($regs:expr, 9) => { $regs.touch_pad9() }; } -/// Common functionality for all touch pads -macro_rules! touch { - (@pin_specific $touch_num:expr, true) => { - paste::paste! { - RTC_IO::regs().[< touch_pad $touch_num >]().write(|w| unsafe { - w.xpd().set_bit(); - // clear input_enable - w.fun_ie().clear_bit(); - // Connect pin to analog / RTC module instead of standard GPIO - w.mux_sel().set_bit(); - // Disable pull-up and pull-down resistors on the pin - w.rue().clear_bit(); - w.rde().clear_bit(); - w.tie_opt().clear_bit(); - // Select function "RTC function 1" (GPIO) for analog use - w.fun_sel().bits(0b00) - }); - } - }; +#[rustfmt::skip] +macro_rules! touch_out_th_field { + ($accessor:expr, 0) => { $accessor.touch_out_th0() }; + ($accessor:expr, 1) => { $accessor.touch_out_th1() }; + ($accessor:expr, 2) => { $accessor.touch_out_th0() }; + ($accessor:expr, 3) => { $accessor.touch_out_th1() }; + ($accessor:expr, 4) => { $accessor.touch_out_th0() }; + ($accessor:expr, 5) => { $accessor.touch_out_th1() }; + ($accessor:expr, 6) => { $accessor.touch_out_th0() }; + ($accessor:expr, 7) => { $accessor.touch_out_th1() }; + ($accessor:expr, 8) => { $accessor.touch_out_th0() }; + ($accessor:expr, 9) => { $accessor.touch_out_th1() }; +} - (@pin_specific $touch_num:expr, false) => { - paste::paste! { - RTC_IO::regs().[< touch_pad $touch_num >]().write(|w| { - w.xpd().set_bit(); - w.tie_opt().clear_bit() - }); - } - }; +#[rustfmt::skip] +macro_rules! touch_meas_out_field { + ($accessor:expr, 0) => { $accessor.touch_meas_out0() }; + ($accessor:expr, 1) => { $accessor.touch_meas_out1() }; + ($accessor:expr, 2) => { $accessor.touch_meas_out0() }; + ($accessor:expr, 3) => { $accessor.touch_meas_out1() }; + ($accessor:expr, 4) => { $accessor.touch_meas_out0() }; + ($accessor:expr, 5) => { $accessor.touch_meas_out1() }; + ($accessor:expr, 6) => { $accessor.touch_meas_out0() }; + ($accessor:expr, 7) => { $accessor.touch_meas_out1() }; + ($accessor:expr, 8) => { $accessor.touch_meas_out0() }; + ($accessor:expr, 9) => { $accessor.touch_meas_out1() }; +} +/// Common functionality for all touch pads +macro_rules! touch { ( $( - ( - $touch_num:literal, $pin_num:literal, $touch_out_reg:expr, $touch_thres_reg:expr, $normal_pin:literal - ) + ($touch_num:tt, $pin_peri:ident $(, $pad_register_has_all_fields:literal)?) )+ ) => { $( - impl $crate::gpio::TouchPin for paste::paste!($crate::peripherals::[]<'_>) { + impl $crate::gpio::TouchPin for $crate::peripherals::$pin_peri<'_> { fn set_touch(&self, _: $crate::private::Internal) { use $crate::peripherals::{GPIO, RTC_IO, SENS}; use $crate::gpio::RtcPin; @@ -190,30 +213,50 @@ macro_rules! touch { rtcio .enable_w1tc() .write(|w| unsafe { w.enable_w1tc().bits(1 << self.rtc_number()) }); - paste::paste! { - sens . $touch_thres_reg () - .write(|w| unsafe { - w. [] ().bits( - 0b0 // Default: 0 for esp32 gets overridden later anyway. - ) - }); - touch!( @pin_specific $touch_num, $normal_pin ); + touch_thres_reg!(sens, $touch_num).write(|w| unsafe { + touch_out_th_field!(w, $touch_num).bits( + 0b0 // Default: 0 for esp32 gets overridden later anyway. + ) + }); - // enable the pin - sens.sar_touch_enable().modify(|r, w| unsafe { - w.touch_pad_worken().bits( - r.touch_pad_worken().bits() | ( 1 << $touch_num ) - ) - }); - } + touch_pad_reg!(RTC_IO::regs(), $touch_num).write( + #[allow(unused_unsafe)] + |w| unsafe { + w.xpd().set_bit(); + w.tie_opt().clear_bit(); + + // touch_pad8 and 9 are missing a few fields + $( + crate::ignore!($pad_register_has_all_fields); + + // clear input_enable + w.fun_ie().clear_bit(); + // Connect pin to analog / RTC module instead of standard GPIO + w.mux_sel().set_bit(); + // Disable pull-up and pull-down resistors on the pin + w.rue().clear_bit(); + w.rde().clear_bit(); + // Select function "RTC function 1" (GPIO) for analog use + w.fun_sel().bits(0b00); + )? + + w + } + ); + + // enable the pin + sens.sar_touch_enable().modify(|r, w| unsafe { + w.touch_pad_worken().bits( + r.touch_pad_worken().bits() | ( 1 << $touch_num ) + ) + }); } fn touch_measurement(&self, _: $crate::private::Internal) -> u16 { - paste::paste! { - $crate::peripherals::SENS::regs() . $touch_out_reg ().read() - . [] ().bits() - } + let regs = $crate::peripherals::SENS::regs(); + let reg = touch_out_reg!(regs, $touch_num).read(); + touch_meas_out_field!(reg, $touch_num).bits() } fn touch_nr(&self, _: $crate::private::Internal) -> u8 { @@ -221,49 +264,62 @@ macro_rules! touch { } fn set_threshold(&self, threshold: u16, _: $crate::private::Internal) { - paste::paste! { - $crate::peripherals::SENS::regs() . $touch_thres_reg () - .write(|w| unsafe { - w. [] ().bits(threshold) - }); - } + let sens = $crate::peripherals::SENS::regs(); + touch_thres_reg!(sens, $touch_num).write(|w| unsafe { + touch_out_th_field!(w, $touch_num).bits(threshold) + }); } })+ }; } +pub(crate) fn errata36(pin: crate::gpio::AnyPin<'_>, pull_up: bool, pull_down: bool) { + use crate::gpio::{Pin, RtcPinWithResistors}; + + for_each_lp_function! { + (all_expanded $( (($_sig:ident, RTC_GPIOn, $_n:literal), $gpio:ident) ),* ) => { + const RTC_IO_PINS: &[u8] = &[ $( $crate::peripherals::$gpio::NUMBER ),* ]; + }; + }; + + if RTC_IO_PINS.contains(&pin.number()) && pin.is_output() { + pin.rtcio_pullup(pull_up); + pin.rtcio_pulldown(pull_down); + } +} + rtcio_analog! { - (36, 0, sensor_pads(), sense1_, sense1 ) - (37, 1, sensor_pads(), sense2_, sense2 ) - (38, 2, sensor_pads(), sense3_, sense3 ) - (39, 3, sensor_pads(), sense4_, sense4 ) - (34, 4, adc_pad(), adc1_, adc1 ) - (35, 5, adc_pad(), adc2_, adc2 ) - (25, 6, pad_dac1(), "", pdac1, true) - (26, 7, pad_dac2(), "", pdac2, true) - (33, 8, xtal_32k_pad(), x32n_, x32n, true) - (32, 9, xtal_32k_pad(), x32p_, x32p, true) - (4, 10, touch_pad0(), "", touch_pad0, true) - (0, 11, touch_pad1(), "", touch_pad1, true) - (2, 12, touch_pad2(), "", touch_pad2, true) - (15, 13, touch_pad3(), "", touch_pad3, true) - (13, 14, touch_pad4(), "", touch_pad4, true) - (12, 15, touch_pad5(), "", touch_pad5, true) - (14, 16, touch_pad6(), "", touch_pad6, true) - (27, 17, touch_pad7(), "", touch_pad7, true) + (GPIO36, 0, sensor_pads(), sense1_, sense1 ) + (GPIO37, 1, sensor_pads(), sense2_, sense2 ) + (GPIO38, 2, sensor_pads(), sense3_, sense3 ) + (GPIO39, 3, sensor_pads(), sense4_, sense4 ) + (GPIO34, 4, adc_pad(), adc1_, adc1 ) + (GPIO35, 5, adc_pad(), adc2_, adc2 ) + (GPIO25, 6, pad_dac1(), "", pdac1 ) + (GPIO26, 7, pad_dac2(), "", pdac2 ) + (GPIO33, 8, xtal_32k_pad(), x32n_, x32n ) + (GPIO32, 9, xtal_32k_pad(), x32p_, x32p ) + (GPIO4, 10, touch_pad0(), "", touch_pad0) + (GPIO0, 11, touch_pad1(), "", touch_pad1) + (GPIO2, 12, touch_pad2(), "", touch_pad2) + (GPIO15, 13, touch_pad3(), "", touch_pad3) + (GPIO13, 14, touch_pad4(), "", touch_pad4) + (GPIO12, 15, touch_pad5(), "", touch_pad5) + (GPIO14, 16, touch_pad6(), "", touch_pad6) + (GPIO27, 17, touch_pad7(), "", touch_pad7) } touch! { - // touch_nr, pin_nr, touch_out_reg, touch_thres_reg, normal_pin - (0, 4, sar_touch_out1, sar_touch_thres1, true) - (1, 0, sar_touch_out1, sar_touch_thres1, true) - (2, 2, sar_touch_out2, sar_touch_thres2, true) - (3, 15, sar_touch_out2, sar_touch_thres2, true) - (4, 13, sar_touch_out3, sar_touch_thres3, true) - (5, 12, sar_touch_out3, sar_touch_thres3, true) - (6, 14, sar_touch_out4, sar_touch_thres4, true) - (7, 27, sar_touch_out4, sar_touch_thres4, true) - // --- - (8, 33, sar_touch_out5, sar_touch_thres5, false) - (9, 32, sar_touch_out5, sar_touch_thres5, false) + // touch_nr, pin_nr, normal_pin + (0, GPIO4, true) + (1, GPIO0, true) + (2, GPIO2, true) + (3, GPIO15, true) + (4, GPIO13, true) + (5, GPIO12, true) + (6, GPIO14, true) + (7, GPIO27, true) + // --- touch_pad8 and 9 are missing a few fields + (8, GPIO33) + (9, GPIO32) } diff --git a/esp-hal/src/soc/esp32s2/psram.rs b/esp-hal/src/soc/esp32s2/psram.rs index 9392628c82b..4d01d379072 100644 --- a/esp-hal/src/soc/esp32s2/psram.rs +++ b/esp-hal/src/soc/esp32s2/psram.rs @@ -336,7 +336,7 @@ pub(crate) mod utils { PsramCmdSpi = 1, } - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] #[inline(always)] fn psram_exec_cmd( mode: CommandMode, @@ -402,7 +402,7 @@ pub(crate) mod utils { } } - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] #[inline(always)] fn _psram_exec_cmd( cmd: u16, @@ -465,12 +465,7 @@ pub(crate) mod utils { match mode { CommandMode::PsramCmdQpi => { esp_rom_spi_set_op_mode(1, ESP_ROM_SPIFLASH_QIO_MODE); - // this should be `fcmd_quad` - apparently our ESP32-S2 SVD isn't correct for - // SPI1 and SPI0. i.e. GP-SPI vs MEM-SPI - // - // TODO fix the SVD and change this back! - // (i.e. in our SVD FCMD_QUAD is bit 9 while it should be bit 8) - SPI1::regs().ctrl().modify(|_, w| w.fcmd_dual().set_bit()); + SPI1::regs().ctrl().modify(|_, w| w.fcmd_quad().set_bit()); } CommandMode::PsramCmdSpi => { esp_rom_spi_set_op_mode(1, ESP_ROM_SPIFLASH_SLOWRD_MODE); diff --git a/esp-hal/src/soc/esp32s3/psram.rs b/esp-hal/src/soc/esp32s3/psram.rs index 647a6f04bd0..aaa8f939bdc 100644 --- a/esp-hal/src/soc/esp32s3/psram.rs +++ b/esp-hal/src/soc/esp32s3/psram.rs @@ -566,7 +566,7 @@ pub(crate) mod utils { PsramCmdSpi = 1, } - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] #[ram] fn psram_exec_cmd( mode: CommandMode, @@ -632,7 +632,7 @@ pub(crate) mod utils { } } - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] #[ram] fn _psram_exec_cmd( cmd: u16, diff --git a/esp-hal/src/soc/mod.rs b/esp-hal/src/soc/mod.rs index 25e31039969..96910ca37ac 100644 --- a/esp-hal/src/soc/mod.rs +++ b/esp-hal/src/soc/mod.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(feature = "rt"), expect(unused))] + use core::ops::Range; use portable_atomic::{AtomicU8, Ordering}; @@ -142,6 +144,7 @@ pub(crate) fn addr_in_range(addr: usize, range: Range) -> bool { range.contains(&addr) } +#[cfg(feature = "rt")] #[cfg(riscv)] #[unsafe(export_name = "hal_main")] fn hal_main(a0: usize, a1: usize, a2: usize) -> ! { @@ -158,6 +161,7 @@ fn hal_main(a0: usize, a1: usize, a2: usize) -> ! { } #[cfg(xtensa)] +#[cfg(feature = "rt")] #[unsafe(no_mangle)] #[cfg_attr(esp32s3, unsafe(link_section = ".rwtext"))] unsafe extern "C" fn ESP32Reset() -> ! { @@ -234,11 +238,13 @@ unsafe extern "C" fn ESP32Reset() -> ! { unsafe { xtensa_lx_rt::Reset() } } +#[cfg(feature = "rt")] #[unsafe(export_name = "__stack_chk_fail")] unsafe extern "C" fn stack_chk_fail() { panic!("Stack corruption detected"); } +#[cfg(feature = "rt")] fn setup_stack_guard() { unsafe extern "C" { static mut __stack_chk_guard: u32; diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 18754fae58b..db2f5a973ad 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -2927,7 +2927,6 @@ impl DmaDriver { self.driver.regs() } - #[allow(clippy::too_many_arguments)] #[cfg_attr(place_spi_master_driver_in_ram, ram)] unsafe fn start_transfer_dma( &self, @@ -3696,7 +3695,7 @@ impl Driver { Ok(()) } - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] fn setup_half_duplex( &self, is_write: bool, diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index 4da732dec3d..1e49fdeda80 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -458,7 +458,6 @@ pub mod dma { self.info.regs() } - #[allow(clippy::too_many_arguments)] unsafe fn start_transfer_dma( &self, read_buffer_len: usize, diff --git a/esp-hal/src/sync.rs b/esp-hal/src/sync.rs index 0cfd402fefc..6ab06c92574 100644 --- a/esp-hal/src/sync.rs +++ b/esp-hal/src/sync.rs @@ -146,7 +146,7 @@ mod single_core { if #[cfg(riscv)] { if token != 0 { unsafe { - esp_riscv_rt::riscv::interrupt::enable(); + riscv::interrupt::enable(); } } } else if #[cfg(xtensa)] { diff --git a/esp-hal/src/system.rs b/esp-hal/src/system.rs index be20a72b1f8..60750ceb934 100755 --- a/esp-hal/src/system.rs +++ b/esp-hal/src/system.rs @@ -226,6 +226,7 @@ static PERIPHERAL_REF_COUNT: Mutex> = /// Disable all peripherals. /// /// Peripherals listed in [KEEP_ENABLED] are NOT disabled. +#[cfg_attr(not(feature = "rt"), expect(dead_code))] pub(crate) fn disable_peripherals() { // Take the critical section up front to avoid taking it multiple times. critical_section::with(|cs| { diff --git a/esp-hal/src/time.rs b/esp-hal/src/time.rs index d8bdff89a68..000205d8deb 100644 --- a/esp-hal/src/time.rs +++ b/esp-hal/src/time.rs @@ -746,7 +746,7 @@ fn now() -> Instant { Instant::from_ticks(ticks / div) } -#[cfg(esp32)] +#[cfg(all(esp32, feature = "rt"))] pub(crate) fn time_init() { let apb = crate::Clocks::get().apb_clock.as_hz(); // we assume 80MHz APB clock source - there is no way to configure it in a diff --git a/esp-hal/src/timer/timg.rs b/esp-hal/src/timer/timg.rs index ff2502ea5d6..877f932c34d 100644 --- a/esp-hal/src/timer/timg.rs +++ b/esp-hal/src/timer/timg.rs @@ -685,20 +685,13 @@ where #[cfg_attr(esp32, allow(unused_unsafe))] reg_block.wdtconfig0().write(|w| unsafe { - w.wdt_en() - .bit(true) - .wdt_stg0() - .bits(MwdtStageAction::ResetSystem as u8) - .wdt_cpu_reset_length() - .bits(7) - .wdt_sys_reset_length() - .bits(7) - .wdt_stg1() - .bits(MwdtStageAction::Off as u8) - .wdt_stg2() - .bits(MwdtStageAction::Off as u8) - .wdt_stg3() - .bits(MwdtStageAction::Off as u8) + w.wdt_en().bit(true); + w.wdt_stg0().bits(MwdtStageAction::ResetSystem as u8); + w.wdt_cpu_reset_length().bits(7); + w.wdt_sys_reset_length().bits(7); + w.wdt_stg1().bits(MwdtStageAction::Off as u8); + w.wdt_stg2().bits(MwdtStageAction::Off as u8); + w.wdt_stg3().bits(MwdtStageAction::Off as u8) }); #[cfg(any(esp32c2, esp32c3, esp32c6))] @@ -733,32 +726,39 @@ where /// Set the timeout, in microseconds, of the watchdog timer pub fn set_timeout(&mut self, stage: MwdtStage, timeout: Duration) { - let timeout_raw = (timeout.as_micros() * 10_000 / 125) as u32; + // Assume default 80MHz clock source + let timeout_ticks = timeout.as_micros() * 10_000 / 125; let reg_block = unsafe { &*TG::register_block() }; + let (prescaler, timeout) = if timeout_ticks > u32::MAX as u64 { + let prescaler = timeout_ticks + .div_ceil(u32::MAX as u64 + 1) + .min(u16::MAX as u64) as u16; + let timeout = timeout_ticks + .div_ceil(prescaler as u64) + .min(u32::MAX as u64); + (prescaler, timeout as u32) + } else { + (1, timeout_ticks as u32) + }; + self.set_write_protection(false); - reg_block - .wdtconfig1() - .write(|w| unsafe { w.wdt_clk_prescale().bits(1) }); + reg_block.wdtconfig1().write(|w| unsafe { + #[cfg(timergroup_timg_has_divcnt_rst)] + w.wdt_divcnt_rst().set_bit(); + w.wdt_clk_prescale().bits(prescaler) + }); - unsafe { - match stage { - MwdtStage::Stage0 => reg_block - .wdtconfig2() - .write(|w| w.wdt_stg0_hold().bits(timeout_raw)), - MwdtStage::Stage1 => reg_block - .wdtconfig3() - .write(|w| w.wdt_stg1_hold().bits(timeout_raw)), - MwdtStage::Stage2 => reg_block - .wdtconfig4() - .write(|w| w.wdt_stg2_hold().bits(timeout_raw)), - MwdtStage::Stage3 => reg_block - .wdtconfig5() - .write(|w| w.wdt_stg3_hold().bits(timeout_raw)), - }; - } + let config_register = match stage { + MwdtStage::Stage0 => reg_block.wdtconfig2(), + MwdtStage::Stage1 => reg_block.wdtconfig3(), + MwdtStage::Stage2 => reg_block.wdtconfig4(), + MwdtStage::Stage3 => reg_block.wdtconfig5(), + }; + + config_register.write(|w| unsafe { w.hold().bits(timeout) }); #[cfg(any(esp32c2, esp32c3, esp32c6))] reg_block @@ -779,28 +779,14 @@ where self.set_write_protection(false); - match stage { - MwdtStage::Stage0 => { - reg_block - .wdtconfig0() - .modify(|_, w| unsafe { w.wdt_stg0().bits(action as u8) }); - } - MwdtStage::Stage1 => { - reg_block - .wdtconfig0() - .modify(|_, w| unsafe { w.wdt_stg1().bits(action as u8) }); - } - MwdtStage::Stage2 => { - reg_block - .wdtconfig0() - .modify(|_, w| unsafe { w.wdt_stg2().bits(action as u8) }); - } - MwdtStage::Stage3 => { - reg_block - .wdtconfig0() - .modify(|_, w| unsafe { w.wdt_stg3().bits(action as u8) }); + reg_block.wdtconfig0().modify(|_, w| unsafe { + match stage { + MwdtStage::Stage0 => w.wdt_stg0().bits(action as u8), + MwdtStage::Stage1 => w.wdt_stg1().bits(action as u8), + MwdtStage::Stage2 => w.wdt_stg2().bits(action as u8), + MwdtStage::Stage3 => w.wdt_stg3().bits(action as u8), } - } + }); self.set_write_protection(true); } diff --git a/esp-hal/src/twai/filter.rs b/esp-hal/src/twai/filter.rs index 12bb8b0a38a..1539d982fdd 100644 --- a/esp-hal/src/twai/filter.rs +++ b/esp-hal/src/twai/filter.rs @@ -401,7 +401,7 @@ impl DualStandardFilter { /// The masks indicate which bits of the code the filter should match /// against. Set bits in the mask indicate that the corresponding bit in /// the code should match. - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] pub fn new_from_code_mask( first_id_code: StandardId, first_id_mask: StandardId, diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index 48c0135ab4a..e6aa25ccd09 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -864,7 +864,7 @@ where // Copy the filter to the peripheral. unsafe { - copy_to_data_register(self.regs().data_0().as_ptr(), registers); + copy_to_data_register(self.regs().data(0).as_ptr(), registers); } } @@ -1349,7 +1349,7 @@ pub trait PrivateInstance: crate::private::Sealed { /// Read a frame from the peripheral. fn read_frame(register_block: &RegisterBlock) -> Result { // Read the frame information and extract the frame id format and dlc. - let data_0 = register_block.data_0().read().tx_byte_0().bits(); + let data_0 = register_block.data(0).read().tx_byte().bits(); let is_standard_format = data_0 & (0b1 << 7) == 0; let is_data_frame = data_0 & (0b1 << 6) == 0; @@ -1368,19 +1368,19 @@ fn read_frame(register_block: &RegisterBlock) -> Result> 5); let id = Id::from(StandardId::new(raw_id).unwrap()); - (id, register_block.data_3().as_ptr()) + (id, register_block.data(3).as_ptr()) } else { // Frame uses extended 29 bit id. - let data_1 = register_block.data_1().read().tx_byte_1().bits(); - let data_2 = register_block.data_2().read().tx_byte_2().bits(); - let data_3 = register_block.data_3().read().tx_byte_3().bits(); - let data_4 = register_block.data_4().read().tx_byte_4().bits(); + let data_1 = register_block.data(1).read().tx_byte().bits(); + let data_2 = register_block.data(2).read().tx_byte().bits(); + let data_3 = register_block.data(3).read().tx_byte().bits(); + let data_4 = register_block.data(4).read().tx_byte().bits(); let raw_id: u32 = ((data_1 as u32) << 21) | ((data_2 as u32) << 13) @@ -1388,7 +1388,7 @@ fn read_frame(register_block: &RegisterBlock) -> Result> 3); let id = Id::from(ExtendedId::new(raw_id).unwrap()); - (id, register_block.data_5().as_ptr()) + (id, register_block.data(5).as_ptr()) }; let mut frame = if is_data_frame { @@ -1423,8 +1423,8 @@ fn write_frame(register_block: &RegisterBlock, frame: &EspTwaiFrame) { let data_0: u8 = (frame_format << 7) | (rtr_bit << 6) | (self_reception << 4) | dlc_bits; register_block - .data_0() - .write(|w| unsafe { w.tx_byte_0().bits(data_0) }); + .data(0) + .write(|w| unsafe { w.tx_byte().bits(data_0) }); // Assemble the identifier information of the packet and return where the data // buffer starts. @@ -1433,32 +1433,32 @@ fn write_frame(register_block: &RegisterBlock, frame: &EspTwaiFrame) { let id = id.as_raw(); register_block - .data_1() - .write(|w| unsafe { w.tx_byte_1().bits((id >> 3) as u8) }); + .data(1) + .write(|w| unsafe { w.tx_byte().bits((id >> 3) as u8) }); register_block - .data_2() - .write(|w| unsafe { w.tx_byte_2().bits((id << 5) as u8) }); + .data(2) + .write(|w| unsafe { w.tx_byte().bits((id << 5) as u8) }); - register_block.data_3().as_ptr() + register_block.data(3).as_ptr() } Id::Extended(id) => { let id = id.as_raw(); register_block - .data_1() - .write(|w| unsafe { w.tx_byte_1().bits((id >> 21) as u8) }); + .data(1) + .write(|w| unsafe { w.tx_byte().bits((id >> 21) as u8) }); register_block - .data_2() - .write(|w| unsafe { w.tx_byte_2().bits((id >> 13) as u8) }); + .data(2) + .write(|w| unsafe { w.tx_byte().bits((id >> 13) as u8) }); register_block - .data_3() - .write(|w| unsafe { w.tx_byte_3().bits((id >> 5) as u8) }); + .data(3) + .write(|w| unsafe { w.tx_byte().bits((id >> 5) as u8) }); register_block - .data_4() - .write(|w| unsafe { w.tx_byte_4().bits((id << 3) as u8) }); + .data(4) + .write(|w| unsafe { w.tx_byte().bits((id << 3) as u8) }); - register_block.data_5().as_ptr() + register_block.data(5).as_ptr() } }; diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index 7a754ee8e4f..85287230d70 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -450,6 +450,7 @@ where let rts_pin = PinGuard::new_unconnected(self.uart.info().rts_signal); let tx_pin = PinGuard::new_unconnected(self.uart.info().tx_signal); + let dtr_pin = PinGuard::new_unconnected(self.uart.info().dtr_signal); let mut serial = Uart { rx: UartRx { @@ -463,6 +464,7 @@ where guard: tx_guard, rts_pin, tx_pin, + dtr_pin, }, }; serial.init(config)?; @@ -499,6 +501,7 @@ pub struct UartTx<'d, Dm: DriverMode> { guard: PeripheralGuard, rts_pin: PinGuard, tx_pin: PinGuard, + dtr_pin: PinGuard, } /// UART (Receive) @@ -641,6 +644,7 @@ impl<'d> UartTx<'d, Blocking> { guard: self.guard, rts_pin: self.rts_pin, tx_pin: self.tx_pin, + dtr_pin: self.dtr_pin, } } } @@ -663,6 +667,7 @@ impl<'d> UartTx<'d, Async> { guard: self.guard, rts_pin: self.rts_pin, tx_pin: self.tx_pin, + dtr_pin: self.dtr_pin, } } @@ -746,6 +751,25 @@ where self } + /// Configure DTR pin + #[instability::unstable] + pub fn with_dtr(mut self, dtr: impl PeripheralOutput<'d>) -> Self { + let dtr = dtr.into(); + + dtr.apply_output_config(&OutputConfig::default()); + dtr.set_output_enable(true); + + self.dtr_pin = dtr.connect_with_guard(self.uart.info().dtr_signal); + + self + } + + /// Enable RS485 mode + pub fn with_rs485(self) -> Self { + self.regs().rs485_conf().write(|w| w.rs485_en().set_bit()); + self + } + /// Assign the TX pin for UART instance. /// /// Sets the specified pin to push-pull output and connects it to the UART @@ -1115,6 +1139,18 @@ where self } + /// Inverts polarity of RX signal if `invertedd` + #[instability::unstable] + pub fn with_polarity(self, inverted: bool) -> Self { + self.uart + .info() + .regs() + .conf0() + .modify(|_, w| w.rxd_inv().bit(inverted)); + + self + } + /// Change the configuration. /// /// ## Errors @@ -1609,6 +1645,20 @@ where self } + /// Configure DTR pin + #[instability::unstable] + pub fn with_dtr(mut self, dtr: impl PeripheralOutput<'d>) -> Self { + self.tx = self.tx.with_dtr(dtr); + self + } + + /// Enable RS485 mode + #[instability::unstable] + pub fn with_rs485(mut self) -> Self { + self.tx = self.tx.with_rs485(); + self + } + fn regs(&self) -> &RegisterBlock { // `self.tx.uart` and `self.rx.uart` are the same self.tx.uart.info().regs() @@ -2340,7 +2390,7 @@ pub(super) fn intr_handler(uart: &Info, state: &State) { } /// Low-power UART -#[cfg(soc_has_lp_uart)] +#[cfg(lp_uart)] #[instability::unstable] pub mod lp_uart { use crate::{ @@ -2609,6 +2659,9 @@ pub struct Info { /// RTS (Request to Send) pin pub rts_signal: OutputSignal, + + /// DTR (Data Terminal Ready) pin + pub dtr_signal: OutputSignal, } /// Peripheral state for a UART instance. @@ -2631,8 +2684,8 @@ pub struct State { impl Info { // Currently we don't support merging adjacent FIFO memory, so the max size is // 128 bytes, the max threshold is 127 bytes. - const UART_FIFO_SIZE: u16 = 128; - const RX_FIFO_MAX_THRHD: u16 = 127; + const UART_FIFO_SIZE: u16 = property!("uart.ram_size"); + const RX_FIFO_MAX_THRHD: u16 = Self::UART_FIFO_SIZE - 1; const TX_FIFO_MAX_THRHD: u16 = Self::RX_FIFO_MAX_THRHD; /// Returns the register block for this UART instance. @@ -3348,7 +3401,7 @@ impl PartialEq for Info { unsafe impl Sync for Info {} for_each_uart! { - ($inst:ident, $peri:ident, $rxd:ident, $txd:ident, $cts:ident, $rts:ident) => { + ($inst:ident, $peri:ident, $rxd:ident, $txd:ident, $cts:ident, $rts:ident, $dtr:ident) => { impl Instance for crate::peripherals::$inst<'_> { fn parts(&self) -> (&'static Info, &'static State) { #[crate::handler] @@ -3371,6 +3424,7 @@ for_each_uart! { rx_signal: InputSignal::$rxd, cts_signal: InputSignal::$cts, rts_signal: OutputSignal::$rts, + dtr_signal: OutputSignal::$dtr, }; (&PERIPHERAL, &STATE) } diff --git a/esp-ieee802154/CHANGELOG.md b/esp-ieee802154/CHANGELOG.md index 551ad1fd48d..8ec91231aa5 100644 --- a/esp-ieee802154/CHANGELOG.md +++ b/esp-ieee802154/CHANGELOG.md @@ -12,9 +12,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- `esp_ieee802154::Ieee802154::new` no longer requires the `RADIO_CLK` peripheral (#3687) - -- MSRV is now 1.88.0 (#3742) ### Fixed @@ -22,6 +19,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [v0.8.0] - 2025-07-16 + +### Changed + +- `esp_ieee802154::Ieee802154::new` no longer requires the `RADIO_CLK` peripheral (#3687) +- MSRV is now 1.88.0 (#3742) + ## [v0.7.0] - 2025-06-03 ### Changed @@ -90,4 +94,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [0.6.0]: https://github.com/esp-rs/esp-hal/releases/tag/esp-ieee802154-v0.6.0 [v0.7.0]: https://github.com/esp-rs/esp-hal/compare/esp-ieee802154-v0.6.0...esp-ieee802154-v0.7.0 -[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-ieee802154-v0.7.0...HEAD +[v0.8.0]: https://github.com/esp-rs/esp-hal/compare/esp-ieee802154-v0.7.0...esp-ieee802154-v0.8.0 +[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-ieee802154-v0.8.0...HEAD diff --git a/esp-ieee802154/Cargo.toml b/esp-ieee802154/Cargo.toml index 7620bff8902..92508642550 100644 --- a/esp-ieee802154/Cargo.toml +++ b/esp-ieee802154/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "esp-ieee802154" -version = "0.7.0" +version = "0.8.0" edition = "2024" rust-version = "1.88.0" description = "Low-level IEEE 802.15.4 driver for the ESP32-C6 and ESP32-H2" @@ -21,7 +21,7 @@ test = false [dependencies] cfg-if = "1.0.0" critical-section = "1.2.0" -esp-hal = { version = "1.0.0-beta.1", path = "../esp-hal", features = ["requires-unstable"] } +esp-hal = { version = "1.0.0-rc.0", path = "../esp-hal", default-features = false, features = ["requires-unstable"] } # ⚠️ Unstable dependencies that are part of the public API heapless = "0.8.0" @@ -29,7 +29,7 @@ heapless = "0.8.0" # Unstable dependencies that are not (strictly) part of the public API byte = "0.2.7" document-features = "0.2.11" -esp-config = { version = "0.4.0", path = "../esp-config" } +esp-config = { version = "0.5.0", path = "../esp-config" } esp-wifi-sys = "0.7.1" ieee802154 = "0.6.1" @@ -38,7 +38,7 @@ defmt = { version = "1.0.1", optional = true } log-04 = { package = "log", version = "0.4.27", optional = true } [build-dependencies] -esp-config = { version = "0.4.0", path = "../esp-config" } +esp-config = { version = "0.5.0", path = "../esp-config" } [features] diff --git a/esp-ieee802154/MIGRATING-0.7.0.md b/esp-ieee802154/MIGRATING-0.7.0.md index 7a02cebc50a..6764a9a4b8c 100644 --- a/esp-ieee802154/MIGRATING-0.7.0.md +++ b/esp-ieee802154/MIGRATING-0.7.0.md @@ -1 +1 @@ -# Migration Guide from 0.7.0 to {{currentVersion}} +# Migration Guide from 0.7.0 to 0.8.0 diff --git a/esp-ieee802154/src/hal.rs b/esp-ieee802154/src/hal.rs index 430e9cebfe0..c2c4aa1ec5b 100644 --- a/esp-ieee802154/src/hal.rs +++ b/esp-ieee802154/src/hal.rs @@ -2,6 +2,7 @@ use core::ops::{BitAnd, BitOr}; use esp_hal::peripherals::IEEE802154; +use super::IEEE802154_FRAME_EXT_ADDR_SIZE; use crate::pib::CcaMode; #[allow(unused)] @@ -276,50 +277,34 @@ pub(crate) fn set_multipan_enable_mask(mask: u8) { #[inline(always)] pub(crate) fn set_multipan_panid(index: MultipanIndex, panid: u16) { - unsafe { - let pan_id = IEEE802154::regs() - .inf0_pan_id() - .as_ptr() - .offset(4 * index as isize); - pan_id.write_volatile(panid as u32); - } + IEEE802154::regs() + .inf(index as usize) + .pan_id() + .write(|w| unsafe { w.pan_id().bits(panid) }); } #[inline(always)] pub(crate) fn set_multipan_short_addr(index: MultipanIndex, value: u16) { - unsafe { - let short_addr = IEEE802154::regs() - .inf0_short_addr() - .as_ptr() - .offset(4 * index as isize); - short_addr.write_volatile(value as u32); - } + IEEE802154::regs() + .inf(index as usize) + .short_addr() + .write(|w| unsafe { w.short_addr().bits(value) }); } #[inline(always)] -pub(crate) fn set_multipan_ext_addr(index: MultipanIndex, ext_addr: *const u8) { - unsafe { - let mut ext_addr_ptr = IEEE802154::regs() - .inf0_extend_addr0() - .as_ptr() - .offset(4 * index as isize); - - ext_addr_ptr.write_volatile( - (ext_addr.offset(0).read_volatile() as u32) - | ((ext_addr.offset(1).read_volatile() as u32) << 8) - | ((ext_addr.offset(2).read_volatile() as u32) << 16) - | ((ext_addr.offset(3).read_volatile() as u32) << 24), - ); +pub(crate) fn set_multipan_ext_addr( + index: MultipanIndex, + ext_addr: [u8; IEEE802154_FRAME_EXT_ADDR_SIZE], +) { + let inf = IEEE802154::regs().inf(index as usize); - ext_addr_ptr = ext_addr_ptr.offset(1); + let ext_addr0 = u32::from_le_bytes(unwrap!(ext_addr[0..3].try_into())); + let ext_addr1 = u32::from_le_bytes(unwrap!(ext_addr[4..7].try_into())); - ext_addr_ptr.write_volatile( - (ext_addr.offset(4).read_volatile() as u32) - | ((ext_addr.offset(5).read_volatile() as u32) << 8) - | ((ext_addr.offset(6).read_volatile() as u32) << 16) - | ((ext_addr.offset(7).read_volatile() as u32) << 24), - ); - } + inf.extend_addr0() + .write(|w| unsafe { w.extend_addr0().bits(ext_addr0) }); + inf.extend_addr1() + .write(|w| unsafe { w.extend_addr1().bits(ext_addr1) }); } #[inline(always)] diff --git a/esp-ieee802154/src/pib.rs b/esp-ieee802154/src/pib.rs index aea77b4aa8d..189adc1e4af 100644 --- a/esp-ieee802154/src/pib.rs +++ b/esp-ieee802154/src/pib.rs @@ -222,7 +222,7 @@ fn ieee802154_set_multipan_hal(pib: &Pib) { if (pib.multipan_mask & (1 << index)) != 0 { set_multipan_panid(index.into(), pib.panid[index]); set_multipan_short_addr(index.into(), pib.short_addr[index]); - set_multipan_ext_addr(index.into(), pib.ext_addr[index].as_ptr()); + set_multipan_ext_addr(index.into(), pib.ext_addr[index]); } } } diff --git a/esp-lp-hal/CHANGELOG.md b/esp-lp-hal/CHANGELOG.md index 0b66587890e..cc3523ab3df 100644 --- a/esp-lp-hal/CHANGELOG.md +++ b/esp-lp-hal/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Fixed size of LP_UART's RAM block (#3812) ### Removed diff --git a/esp-lp-hal/Cargo.toml b/esp-lp-hal/Cargo.toml index 1b2c434294f..6a9365c137b 100644 --- a/esp-lp-hal/Cargo.toml +++ b/esp-lp-hal/Cargo.toml @@ -29,12 +29,16 @@ esp32c6-lp = { version = "0.3.0", features = ["critical-section"], option esp32s2-ulp = { version = "0.3.0", features = ["critical-section"], optional = true } esp32s3-ulp = { version = "0.3.0", features = ["critical-section"], optional = true } nb = { version = "1.1.0", optional = true } -procmacros = { version = "0.18.0", package = "esp-hal-procmacros", path = "../esp-hal-procmacros" } +procmacros = { version = "0.19.0", package = "esp-hal-procmacros", path = "../esp-hal-procmacros" } riscv = { version = "0.11.1", features = ["critical-section-single-hart"] } +esp-metadata-generated = { version = "0.1.0", path = "../esp-metadata-generated" } [dev-dependencies] panic-halt = "0.2.0" +[build-dependencies] +esp-metadata-generated = { version = "0.1.0", path = "../esp-metadata-generated", features = ["build-script"] } + [features] default = ["embedded-hal"] @@ -47,11 +51,11 @@ debug = [ # Chip Support Feature Flags # Target the ESP32-C6. -esp32c6 = ["dep:esp32c6-lp", "procmacros/is-lp-core", "dep:nb"] +esp32c6 = ["dep:esp32c6-lp", "esp-metadata-generated/esp32c6", "procmacros/is-lp-core", "dep:nb"] # Target the ESP32-S2. -esp32s2 = ["dep:esp32s2-ulp", "procmacros/is-ulp-core"] +esp32s2 = ["dep:esp32s2-ulp", "esp-metadata-generated/esp32s2", "procmacros/is-ulp-core"] # Target the ESP32-S3. -esp32s3 = ["dep:esp32s3-ulp", "procmacros/is-ulp-core"] +esp32s3 = ["dep:esp32s3-ulp", "esp-metadata-generated/esp32s3", "procmacros/is-ulp-core"] #! ### Trait Implementation Feature Flags ## Implement the traits defined in the `1.0.0` releases of `embedded-hal` and diff --git a/esp-lp-hal/build.rs b/esp-lp-hal/build.rs index 23cc4e6fb5f..f07dca41629 100644 --- a/esp-lp-hal/build.rs +++ b/esp-lp-hal/build.rs @@ -1,48 +1,26 @@ use std::{env, error::Error, fs, path::PathBuf}; -#[macro_export] -macro_rules! assert_unique_used_features { - ($($feature:literal),+ $(,)?) => { - assert!( - (0 $(+ cfg!(feature = $feature) as usize)+ ) == 1, - "Exactly one of the following features must be enabled: {}", - [$($feature),+].join(", ") - ); - }; -} +use esp_metadata_generated::Chip; fn main() -> Result<(), Box> { - // NOTE: update when adding new device support! - // Ensure that exactly one chip has been specified: - assert_unique_used_features!("esp32c6", "esp32s2", "esp32s3"); - - // NOTE: update when adding new device support! // Determine the name of the configured device: - let device_name = if cfg!(feature = "esp32c6") { - "esp32c6" - } else if cfg!(feature = "esp32s2") { - "esp32s2" - } else if cfg!(feature = "esp32s3") { - "esp32s3" - } else { - unreachable!() // We've confirmed exactly one known device was selected - }; + let chip = Chip::from_cargo_feature()?; // Define all necessary configuration symbols for the configured device: - println!("cargo:rustc-cfg={device_name}"); + chip.define_cfgs(); + + // Copy the required linker script to the `out` directory: + let source_file = match chip { + Chip::Esp32c6 => "ld/link-lp.x", + Chip::Esp32s2 | Chip::Esp32s3 => "ld/link-ulp.x", + _ => unreachable!(), + }; // Put the linker script somewhere the linker can find it: let out = PathBuf::from(env::var_os("OUT_DIR").unwrap()); println!("cargo:rustc-link-search={}", out.display()); - - // Copy the required linker script to the `out` directory: - if cfg!(feature = "esp32c6") { - fs::copy("ld/link-lp.x", out.join("link.x"))?; - println!("cargo:rerun-if-changed=ld/link-lp.x"); - } else if cfg!(feature = "esp32s2") || cfg!(feature = "esp32s3") { - fs::copy("ld/link-ulp.x", out.join("link.x"))?; - println!("cargo:rerun-if-changed=ld/link-ulp.x"); - } + fs::copy(source_file, out.join("link.x"))?; + println!("cargo:rerun-if-changed=ld/link-ulp.x"); // Done! Ok(()) diff --git a/esp-lp-hal/src/i2c.rs b/esp-lp-hal/src/i2c.rs index 726eeb62126..4f69e466f1f 100644 --- a/esp-lp-hal/src/i2c.rs +++ b/esp-lp-hal/src/i2c.rs @@ -12,7 +12,7 @@ const I2C_LL_INTR_MASK: u32 = (1 << LP_I2C_TRANS_COMPLETE_INT_ST_S) | (1 << LP_I2C_END_DETECT_INT_ST_S) | (1 << LP_I2C_NACK_INT_ST_S); -const LP_I2C_FIFO_LEN: u32 = 16; +const LP_I2C_FIFO_LEN: u32 = property!("lp_i2c_master.fifo_size"); #[doc(hidden)] pub unsafe fn conjure() -> LpI2c { diff --git a/esp-lp-hal/src/lib.rs b/esp-lp-hal/src/lib.rs index 7f8c246e759..7760927d950 100644 --- a/esp-lp-hal/src/lib.rs +++ b/esp-lp-hal/src/lib.rs @@ -18,13 +18,17 @@ #![deny(missing_docs)] #![no_std] +#[allow(unused_imports, reason = "Only used for some MCUs currently")] +#[macro_use] +extern crate esp_metadata_generated; + use core::arch::global_asm; pub mod delay; pub mod gpio; -#[cfg(esp32c6)] +#[cfg(lp_i2c_master)] pub mod i2c; -#[cfg(esp32c6)] +#[cfg(lp_uart)] pub mod uart; #[cfg(feature = "esp32c6")] diff --git a/esp-lp-hal/src/uart.rs b/esp-lp-hal/src/uart.rs index a0eceb9d5e4..c0f1b985891 100644 --- a/esp-lp-hal/src/uart.rs +++ b/esp-lp-hal/src/uart.rs @@ -36,7 +36,7 @@ use crate::pac::LP_UART; -const UART_FIFO_SIZE: u16 = 128; +const UART_FIFO_SIZE: u16 = property!("lp_uart.ram_size"); #[doc(hidden)] pub unsafe fn conjure() -> LpUart { diff --git a/esp-metadata-generated/Cargo.toml b/esp-metadata-generated/Cargo.toml index f1065c337c0..eb10d0657a4 100644 --- a/esp-metadata-generated/Cargo.toml +++ b/esp-metadata-generated/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "esp-metadata-generated" -version = "0.0.1" +version = "0.1.0" edition = "2024" rust-version = "1.86.0" description = "Generated metadata for Espressif devices" @@ -11,7 +11,7 @@ license = "MIT OR Apache-2.0" [dependencies] [build-dependencies] -esp-metadata = { version = "0.7.0", path = "../esp-metadata" } # TODO: remove +esp-metadata = { version = "0.8.0", path = "../esp-metadata" } # TODO: remove [features] build-script = [] diff --git a/esp-metadata-generated/src/_build_script_utils.rs b/esp-metadata-generated/src/_build_script_utils.rs index d99caa27acc..7159004eea5 100644 --- a/esp-metadata-generated/src/_build_script_utils.rs +++ b/esp-metadata-generated/src/_build_script_utils.rs @@ -278,6 +278,7 @@ impl Chip { "rmt_ram_start=\"1073047552\"", "rmt_channel_ram_size=\"64\"", "timergroup_timg_has_timer1", + "uart_ram_size=\"128\"", "has_dram_region", ], cfgs: &[ @@ -419,6 +420,7 @@ impl Chip { "cargo:rustc-cfg=rmt_ram_start=\"1073047552\"", "cargo:rustc-cfg=rmt_channel_ram_size=\"64\"", "cargo:rustc-cfg=timergroup_timg_has_timer1", + "cargo:rustc-cfg=uart_ram_size=\"128\"", "cargo:rustc-cfg=has_dram_region", ], }, @@ -524,6 +526,8 @@ impl Chip { "i2c_master_ll_intr_mask=\"262143\"", "i2c_master_fifo_size=\"16\"", "interrupts_status_registers=\"2\"", + "timergroup_timg_has_divcnt_rst", + "uart_ram_size=\"128\"", "has_dram_region", ], cfgs: &[ @@ -625,6 +629,8 @@ impl Chip { "cargo:rustc-cfg=i2c_master_ll_intr_mask=\"262143\"", "cargo:rustc-cfg=i2c_master_fifo_size=\"16\"", "cargo:rustc-cfg=interrupts_status_registers=\"2\"", + "cargo:rustc-cfg=timergroup_timg_has_divcnt_rst", + "cargo:rustc-cfg=uart_ram_size=\"128\"", "cargo:rustc-cfg=has_dram_region", ], }, @@ -750,6 +756,8 @@ impl Chip { "interrupts_status_registers=\"2\"", "rmt_ram_start=\"1610703872\"", "rmt_channel_ram_size=\"48\"", + "timergroup_timg_has_divcnt_rst", + "uart_ram_size=\"128\"", "has_dram_region", ], cfgs: &[ @@ -871,6 +879,8 @@ impl Chip { "cargo:rustc-cfg=interrupts_status_registers=\"2\"", "cargo:rustc-cfg=rmt_ram_start=\"1610703872\"", "cargo:rustc-cfg=rmt_channel_ram_size=\"48\"", + "cargo:rustc-cfg=timergroup_timg_has_divcnt_rst", + "cargo:rustc-cfg=uart_ram_size=\"128\"", "cargo:rustc-cfg=has_dram_region", ], }, @@ -990,6 +1000,7 @@ impl Chip { "gpio", "hmac", "i2c_master", + "lp_i2c_master", "i2s", "interrupts", "io_mux", @@ -1010,6 +1021,7 @@ impl Chip { "timergroup", "twai", "uart", + "lp_uart", "ulp_riscv", "usb_serial_jtag", "wifi", @@ -1043,9 +1055,13 @@ impl Chip { "i2c_master_max_bus_timeout=\"31\"", "i2c_master_ll_intr_mask=\"262143\"", "i2c_master_fifo_size=\"32\"", + "lp_i2c_master_fifo_size=\"16\"", "interrupts_status_registers=\"3\"", "rmt_ram_start=\"1610638336\"", "rmt_channel_ram_size=\"48\"", + "timergroup_timg_has_divcnt_rst", + "uart_ram_size=\"128\"", + "lp_uart_ram_size=\"32\"", "wifi_has_wifi6", "has_dram_region", ], @@ -1162,6 +1178,7 @@ impl Chip { "cargo:rustc-cfg=gpio", "cargo:rustc-cfg=hmac", "cargo:rustc-cfg=i2c_master", + "cargo:rustc-cfg=lp_i2c_master", "cargo:rustc-cfg=i2s", "cargo:rustc-cfg=interrupts", "cargo:rustc-cfg=io_mux", @@ -1182,6 +1199,7 @@ impl Chip { "cargo:rustc-cfg=timergroup", "cargo:rustc-cfg=twai", "cargo:rustc-cfg=uart", + "cargo:rustc-cfg=lp_uart", "cargo:rustc-cfg=ulp_riscv", "cargo:rustc-cfg=usb_serial_jtag", "cargo:rustc-cfg=wifi", @@ -1215,9 +1233,13 @@ impl Chip { "cargo:rustc-cfg=i2c_master_max_bus_timeout=\"31\"", "cargo:rustc-cfg=i2c_master_ll_intr_mask=\"262143\"", "cargo:rustc-cfg=i2c_master_fifo_size=\"32\"", + "cargo:rustc-cfg=lp_i2c_master_fifo_size=\"16\"", "cargo:rustc-cfg=interrupts_status_registers=\"3\"", "cargo:rustc-cfg=rmt_ram_start=\"1610638336\"", "cargo:rustc-cfg=rmt_channel_ram_size=\"48\"", + "cargo:rustc-cfg=timergroup_timg_has_divcnt_rst", + "cargo:rustc-cfg=uart_ram_size=\"128\"", + "cargo:rustc-cfg=lp_uart_ram_size=\"32\"", "cargo:rustc-cfg=wifi_has_wifi6", "cargo:rustc-cfg=has_dram_region", ], @@ -1373,6 +1395,8 @@ impl Chip { "interrupts_status_registers=\"2\"", "rmt_ram_start=\"1610642432\"", "rmt_channel_ram_size=\"48\"", + "timergroup_timg_has_divcnt_rst", + "uart_ram_size=\"128\"", "has_dram_region", ], cfgs: &[ @@ -1523,6 +1547,8 @@ impl Chip { "cargo:rustc-cfg=interrupts_status_registers=\"2\"", "cargo:rustc-cfg=rmt_ram_start=\"1610642432\"", "cargo:rustc-cfg=rmt_channel_ram_size=\"48\"", + "cargo:rustc-cfg=timergroup_timg_has_divcnt_rst", + "cargo:rustc-cfg=uart_ram_size=\"128\"", "cargo:rustc-cfg=has_dram_region", ], }, @@ -1669,6 +1695,7 @@ impl Chip { "rmt_channel_ram_size=\"64\"", "spi_master_has_octal", "timergroup_timg_has_timer1", + "uart_ram_size=\"128\"", "has_dram_region", ], cfgs: &[ @@ -1811,6 +1838,7 @@ impl Chip { "cargo:rustc-cfg=rmt_channel_ram_size=\"64\"", "cargo:rustc-cfg=spi_master_has_octal", "cargo:rustc-cfg=timergroup_timg_has_timer1", + "cargo:rustc-cfg=uart_ram_size=\"128\"", "cargo:rustc-cfg=has_dram_region", ], }, @@ -1977,6 +2005,7 @@ impl Chip { "rmt_channel_ram_size=\"48\"", "spi_master_has_octal", "timergroup_timg_has_timer1", + "uart_ram_size=\"128\"", "has_dram_region", ], cfgs: &[ @@ -2139,6 +2168,7 @@ impl Chip { "cargo:rustc-cfg=rmt_channel_ram_size=\"48\"", "cargo:rustc-cfg=spi_master_has_octal", "cargo:rustc-cfg=timergroup_timg_has_timer1", + "cargo:rustc-cfg=uart_ram_size=\"128\"", "cargo:rustc-cfg=has_dram_region", ], }, @@ -2317,6 +2347,7 @@ impl Config { println!("cargo:rustc-check-cfg=cfg(i2c_master_has_arbitration_en)"); println!("cargo:rustc-check-cfg=cfg(i2c_master_has_tx_fifo_watermark)"); println!("cargo:rustc-check-cfg=cfg(i2c_master_bus_timeout_is_exponential)"); + println!("cargo:rustc-check-cfg=cfg(timergroup_timg_has_divcnt_rst)"); println!("cargo:rustc-check-cfg=cfg(esp32c3)"); println!("cargo:rustc-check-cfg=cfg(soc_has_ds)"); println!("cargo:rustc-check-cfg=cfg(soc_has_fe)"); @@ -2372,7 +2403,9 @@ impl Config { println!("cargo:rustc-check-cfg=cfg(lp_core)"); println!("cargo:rustc-check-cfg=cfg(pm_support_beacon_wakeup)"); println!("cargo:rustc-check-cfg=cfg(etm)"); + println!("cargo:rustc-check-cfg=cfg(lp_i2c_master)"); println!("cargo:rustc-check-cfg=cfg(parl_io)"); + println!("cargo:rustc-check-cfg=cfg(lp_uart)"); println!("cargo:rustc-check-cfg=cfg(ulp_riscv)"); println!("cargo:rustc-check-cfg=cfg(ieee802154)"); println!("cargo:rustc-check-cfg=cfg(i2c_master_can_estimate_nack_reason)"); @@ -2430,6 +2463,9 @@ impl Config { "cargo:rustc-check-cfg=cfg(rmt_ram_start, values(\"1073047552\",\"1610703872\",\"1610638336\",\"1610642432\",\"1061250048\",\"1610704896\"))" ); println!("cargo:rustc-check-cfg=cfg(rmt_channel_ram_size, values(\"64\",\"48\"))"); + println!("cargo:rustc-check-cfg=cfg(uart_ram_size, values(\"128\"))"); + println!("cargo:rustc-check-cfg=cfg(lp_i2c_master_fifo_size, values(\"16\"))"); + println!("cargo:rustc-check-cfg=cfg(lp_uart_ram_size, values(\"32\"))"); for cfg in self.cfgs { println!("{cfg}"); } diff --git a/esp-metadata-generated/src/_generated_esp32.rs b/esp-metadata-generated/src/_generated_esp32.rs index a0cecd86505..a7168beafbb 100644 --- a/esp-metadata-generated/src/_generated_esp32.rs +++ b/esp-metadata-generated/src/_generated_esp32.rs @@ -156,6 +156,15 @@ macro_rules! property { ("timergroup.timg_has_timer1") => { true }; + ("timergroup.timg_has_divcnt_rst") => { + false + }; + ("uart.ram_size") => { + 128 + }; + ("uart.ram_size", str) => { + stringify!(128) + }; ("wifi.has_wifi6") => { false }; @@ -210,17 +219,18 @@ macro_rules! for_each_i2c_master { /// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum. /// - `$rx`, `$tx`, `$cts`, `$rts`: signal names. /// -/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)` +/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR)` #[macro_export] #[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))] macro_rules! for_each_uart { ($($pattern:tt => $code:tt;)*) => { macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} } - _for_each_inner!((UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)); - _for_each_inner!((UART1, Uart1, U1RXD, U1TXD, U1CTS, U1RTS)); - _for_each_inner!((UART2, Uart2, U2RXD, U2TXD, U2CTS, U2RTS)); - _for_each_inner!((all(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS), (UART1, Uart1, - U1RXD, U1TXD, U1CTS, U1RTS), (UART2, Uart2, U2RXD, U2TXD, U2CTS, U2RTS))); + _for_each_inner!((UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR)); + _for_each_inner!((UART1, Uart1, U1RXD, U1TXD, U1CTS, U1RTS, U1DTR)); + _for_each_inner!((UART2, Uart2, U2RXD, U2TXD, U2CTS, U2RTS, U2DTR)); + _for_each_inner!((all(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR), (UART1, + Uart1, U1RXD, U1TXD, U1CTS, U1RTS, U1DTR), (UART2, Uart2, U2RXD, U2TXD, U2CTS, + U2RTS, U2DTR))); }; } /// This macro can be used to generate code for each peripheral instance of the SPI master driver. @@ -1131,99 +1141,44 @@ macro_rules! define_io_mux_signals { macro_rules! define_io_mux_reg { () => { pub(crate) fn io_mux_reg(gpio_num: u8) -> &'static crate::pac::io_mux::GPIO0 { - use core::mem::transmute; - - use crate::{pac::io_mux, peripherals::IO_MUX}; - let iomux = IO_MUX::regs(); - unsafe { - match gpio_num { - 0 => transmute::<&'static io_mux::GPIO0, &'static io_mux::GPIO0>(iomux.gpio0()), - 1 => transmute::<&'static io_mux::GPIO1, &'static io_mux::GPIO0>(iomux.gpio1()), - 2 => transmute::<&'static io_mux::GPIO2, &'static io_mux::GPIO0>(iomux.gpio2()), - 3 => transmute::<&'static io_mux::GPIO3, &'static io_mux::GPIO0>(iomux.gpio3()), - 4 => transmute::<&'static io_mux::GPIO4, &'static io_mux::GPIO0>(iomux.gpio4()), - 5 => transmute::<&'static io_mux::GPIO5, &'static io_mux::GPIO0>(iomux.gpio5()), - 6 => transmute::<&'static io_mux::GPIO6, &'static io_mux::GPIO0>(iomux.gpio6()), - 7 => transmute::<&'static io_mux::GPIO7, &'static io_mux::GPIO0>(iomux.gpio7()), - 8 => transmute::<&'static io_mux::GPIO8, &'static io_mux::GPIO0>(iomux.gpio8()), - 9 => transmute::<&'static io_mux::GPIO9, &'static io_mux::GPIO0>(iomux.gpio9()), - 10 => { - transmute::<&'static io_mux::GPIO10, &'static io_mux::GPIO0>(iomux.gpio10()) - } - 11 => { - transmute::<&'static io_mux::GPIO11, &'static io_mux::GPIO0>(iomux.gpio11()) - } - 12 => { - transmute::<&'static io_mux::GPIO12, &'static io_mux::GPIO0>(iomux.gpio12()) - } - 13 => { - transmute::<&'static io_mux::GPIO13, &'static io_mux::GPIO0>(iomux.gpio13()) - } - 14 => { - transmute::<&'static io_mux::GPIO14, &'static io_mux::GPIO0>(iomux.gpio14()) - } - 15 => { - transmute::<&'static io_mux::GPIO15, &'static io_mux::GPIO0>(iomux.gpio15()) - } - 16 => { - transmute::<&'static io_mux::GPIO16, &'static io_mux::GPIO0>(iomux.gpio16()) - } - 17 => { - transmute::<&'static io_mux::GPIO17, &'static io_mux::GPIO0>(iomux.gpio17()) - } - 18 => { - transmute::<&'static io_mux::GPIO18, &'static io_mux::GPIO0>(iomux.gpio18()) - } - 19 => { - transmute::<&'static io_mux::GPIO19, &'static io_mux::GPIO0>(iomux.gpio19()) - } - 20 => { - transmute::<&'static io_mux::GPIO20, &'static io_mux::GPIO0>(iomux.gpio20()) - } - 21 => { - transmute::<&'static io_mux::GPIO21, &'static io_mux::GPIO0>(iomux.gpio21()) - } - 22 => { - transmute::<&'static io_mux::GPIO22, &'static io_mux::GPIO0>(iomux.gpio22()) - } - 23 => { - transmute::<&'static io_mux::GPIO23, &'static io_mux::GPIO0>(iomux.gpio23()) - } - 25 => { - transmute::<&'static io_mux::GPIO25, &'static io_mux::GPIO0>(iomux.gpio25()) - } - 26 => { - transmute::<&'static io_mux::GPIO26, &'static io_mux::GPIO0>(iomux.gpio26()) - } - 27 => { - transmute::<&'static io_mux::GPIO27, &'static io_mux::GPIO0>(iomux.gpio27()) - } - 32 => { - transmute::<&'static io_mux::GPIO32, &'static io_mux::GPIO0>(iomux.gpio32()) - } - 33 => { - transmute::<&'static io_mux::GPIO33, &'static io_mux::GPIO0>(iomux.gpio33()) - } - 34 => { - transmute::<&'static io_mux::GPIO34, &'static io_mux::GPIO0>(iomux.gpio34()) - } - 35 => { - transmute::<&'static io_mux::GPIO35, &'static io_mux::GPIO0>(iomux.gpio35()) - } - 36 => { - transmute::<&'static io_mux::GPIO36, &'static io_mux::GPIO0>(iomux.gpio36()) - } - 37 => { - transmute::<&'static io_mux::GPIO37, &'static io_mux::GPIO0>(iomux.gpio37()) - } - 38 => { - transmute::<&'static io_mux::GPIO38, &'static io_mux::GPIO0>(iomux.gpio38()) - } - 39 => { - transmute::<&'static io_mux::GPIO39, &'static io_mux::GPIO0>(iomux.gpio39()) - } - other => panic!("GPIO {} does not exist", other), - } + let iomux = crate::peripherals::IO_MUX::regs(); + match gpio_num { + 0 => iomux.gpio0(), + 1 => iomux.gpio1(), + 2 => iomux.gpio2(), + 3 => iomux.gpio3(), + 4 => iomux.gpio4(), + 5 => iomux.gpio5(), + 6 => iomux.gpio6(), + 7 => iomux.gpio7(), + 8 => iomux.gpio8(), + 9 => iomux.gpio9(), + 10 => iomux.gpio10(), + 11 => iomux.gpio11(), + 12 => iomux.gpio12(), + 13 => iomux.gpio13(), + 14 => iomux.gpio14(), + 15 => iomux.gpio15(), + 16 => iomux.gpio16(), + 17 => iomux.gpio17(), + 18 => iomux.gpio18(), + 19 => iomux.gpio19(), + 20 => iomux.gpio20(), + 21 => iomux.gpio21(), + 22 => iomux.gpio22(), + 23 => iomux.gpio23(), + 25 => iomux.gpio25(), + 26 => iomux.gpio26(), + 27 => iomux.gpio27(), + 32 => iomux.gpio32(), + 33 => iomux.gpio33(), + 34 => iomux.gpio34(), + 35 => iomux.gpio35(), + 36 => iomux.gpio36(), + 37 => iomux.gpio37(), + 38 => iomux.gpio38(), + 39 => iomux.gpio39(), + other => panic!("GPIO {} does not exist", other), } } }; diff --git a/esp-metadata-generated/src/_generated_esp32c2.rs b/esp-metadata-generated/src/_generated_esp32c2.rs index c9d55a00218..013223313f0 100644 --- a/esp-metadata-generated/src/_generated_esp32c2.rs +++ b/esp-metadata-generated/src/_generated_esp32c2.rs @@ -144,6 +144,15 @@ macro_rules! property { ("timergroup.timg_has_timer1") => { false }; + ("timergroup.timg_has_divcnt_rst") => { + true + }; + ("uart.ram_size") => { + 128 + }; + ("uart.ram_size", str) => { + stringify!(128) + }; ("wifi.has_wifi6") => { false }; @@ -196,16 +205,16 @@ macro_rules! for_each_i2c_master { /// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum. /// - `$rx`, `$tx`, `$cts`, `$rts`: signal names. /// -/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)` +/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR)` #[macro_export] #[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))] macro_rules! for_each_uart { ($($pattern:tt => $code:tt;)*) => { macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} } - _for_each_inner!((UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)); - _for_each_inner!((UART1, Uart1, U1RXD, U1TXD, U1CTS, U1RTS)); - _for_each_inner!((all(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS), (UART1, Uart1, - U1RXD, U1TXD, U1CTS, U1RTS))); + _for_each_inner!((UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR)); + _for_each_inner!((UART1, Uart1, U1RXD, U1TXD, U1CTS, U1RTS, U1DTR)); + _for_each_inner!((all(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR), (UART1, + Uart1, U1RXD, U1TXD, U1CTS, U1RTS, U1DTR))); }; } /// This macro can be used to generate code for each peripheral instance of the SPI master driver. diff --git a/esp-metadata-generated/src/_generated_esp32c3.rs b/esp-metadata-generated/src/_generated_esp32c3.rs index 3cf8472c486..163427b6ff7 100644 --- a/esp-metadata-generated/src/_generated_esp32c3.rs +++ b/esp-metadata-generated/src/_generated_esp32c3.rs @@ -156,6 +156,15 @@ macro_rules! property { ("timergroup.timg_has_timer1") => { false }; + ("timergroup.timg_has_divcnt_rst") => { + true + }; + ("uart.ram_size") => { + 128 + }; + ("uart.ram_size", str) => { + stringify!(128) + }; ("wifi.has_wifi6") => { false }; @@ -208,16 +217,16 @@ macro_rules! for_each_i2c_master { /// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum. /// - `$rx`, `$tx`, `$cts`, `$rts`: signal names. /// -/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)` +/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR)` #[macro_export] #[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))] macro_rules! for_each_uart { ($($pattern:tt => $code:tt;)*) => { macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} } - _for_each_inner!((UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)); - _for_each_inner!((UART1, Uart1, U1RXD, U1TXD, U1CTS, U1RTS)); - _for_each_inner!((all(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS), (UART1, Uart1, - U1RXD, U1TXD, U1CTS, U1RTS))); + _for_each_inner!((UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR)); + _for_each_inner!((UART1, Uart1, U1RXD, U1TXD, U1CTS, U1RTS, U1DTR)); + _for_each_inner!((all(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR), (UART1, + Uart1, U1RXD, U1TXD, U1CTS, U1RTS, U1DTR))); }; } /// This macro can be used to generate code for each peripheral instance of the SPI master driver. diff --git a/esp-metadata-generated/src/_generated_esp32c6.rs b/esp-metadata-generated/src/_generated_esp32c6.rs index 10797947319..15c838ff665 100644 --- a/esp-metadata-generated/src/_generated_esp32c6.rs +++ b/esp-metadata-generated/src/_generated_esp32c6.rs @@ -132,6 +132,12 @@ macro_rules! property { ("i2c_master.fifo_size", str) => { stringify!(32) }; + ("lp_i2c_master.fifo_size") => { + 16 + }; + ("lp_i2c_master.fifo_size", str) => { + stringify!(16) + }; ("interrupts.status_registers") => { 3 }; @@ -156,6 +162,21 @@ macro_rules! property { ("timergroup.timg_has_timer1") => { false }; + ("timergroup.timg_has_divcnt_rst") => { + true + }; + ("uart.ram_size") => { + 128 + }; + ("uart.ram_size", str) => { + stringify!(128) + }; + ("lp_uart.ram_size") => { + 32 + }; + ("lp_uart.ram_size", str) => { + stringify!(32) + }; ("wifi.has_wifi6") => { true }; @@ -208,16 +229,16 @@ macro_rules! for_each_i2c_master { /// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum. /// - `$rx`, `$tx`, `$cts`, `$rts`: signal names. /// -/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)` +/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR)` #[macro_export] #[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))] macro_rules! for_each_uart { ($($pattern:tt => $code:tt;)*) => { macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} } - _for_each_inner!((UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)); - _for_each_inner!((UART1, Uart1, U1RXD, U1TXD, U1CTS, U1RTS)); - _for_each_inner!((all(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS), (UART1, Uart1, - U1RXD, U1TXD, U1CTS, U1RTS))); + _for_each_inner!((UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR)); + _for_each_inner!((UART1, Uart1, U1RXD, U1TXD, U1CTS, U1RTS, U1DTR)); + _for_each_inner!((all(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR), (UART1, + Uart1, U1RXD, U1TXD, U1CTS, U1RTS, U1DTR))); }; } /// This macro can be used to generate code for each peripheral instance of the SPI master driver. diff --git a/esp-metadata-generated/src/_generated_esp32h2.rs b/esp-metadata-generated/src/_generated_esp32h2.rs index b46fa2e7574..629ed7e14ea 100644 --- a/esp-metadata-generated/src/_generated_esp32h2.rs +++ b/esp-metadata-generated/src/_generated_esp32h2.rs @@ -156,6 +156,15 @@ macro_rules! property { ("timergroup.timg_has_timer1") => { false }; + ("timergroup.timg_has_divcnt_rst") => { + true + }; + ("uart.ram_size") => { + 128 + }; + ("uart.ram_size", str) => { + stringify!(128) + }; } /// Macro to get the address range of the given memory region. #[macro_export] @@ -207,16 +216,16 @@ macro_rules! for_each_i2c_master { /// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum. /// - `$rx`, `$tx`, `$cts`, `$rts`: signal names. /// -/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)` +/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR)` #[macro_export] #[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))] macro_rules! for_each_uart { ($($pattern:tt => $code:tt;)*) => { macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} } - _for_each_inner!((UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)); - _for_each_inner!((UART1, Uart1, U1RXD, U1TXD, U1CTS, U1RTS)); - _for_each_inner!((all(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS), (UART1, Uart1, - U1RXD, U1TXD, U1CTS, U1RTS))); + _for_each_inner!((UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR)); + _for_each_inner!((UART1, Uart1, U1RXD, U1TXD, U1CTS, U1RTS, U1DTR)); + _for_each_inner!((all(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR), (UART1, + Uart1, U1RXD, U1TXD, U1CTS, U1RTS, U1DTR))); }; } /// This macro can be used to generate code for each peripheral instance of the SPI master driver. diff --git a/esp-metadata-generated/src/_generated_esp32s2.rs b/esp-metadata-generated/src/_generated_esp32s2.rs index 9c17a876dc8..813737f1e02 100644 --- a/esp-metadata-generated/src/_generated_esp32s2.rs +++ b/esp-metadata-generated/src/_generated_esp32s2.rs @@ -156,6 +156,15 @@ macro_rules! property { ("timergroup.timg_has_timer1") => { true }; + ("timergroup.timg_has_divcnt_rst") => { + false + }; + ("uart.ram_size") => { + 128 + }; + ("uart.ram_size", str) => { + stringify!(128) + }; ("wifi.has_wifi6") => { false }; @@ -210,16 +219,16 @@ macro_rules! for_each_i2c_master { /// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum. /// - `$rx`, `$tx`, `$cts`, `$rts`: signal names. /// -/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)` +/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR)` #[macro_export] #[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))] macro_rules! for_each_uart { ($($pattern:tt => $code:tt;)*) => { macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} } - _for_each_inner!((UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)); - _for_each_inner!((UART1, Uart1, U1RXD, U1TXD, U1CTS, U1RTS)); - _for_each_inner!((all(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS), (UART1, Uart1, - U1RXD, U1TXD, U1CTS, U1RTS))); + _for_each_inner!((UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR)); + _for_each_inner!((UART1, Uart1, U1RXD, U1TXD, U1CTS, U1RTS, U1DTR)); + _for_each_inner!((all(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR), (UART1, + Uart1, U1RXD, U1TXD, U1CTS, U1RTS, U1DTR))); }; } /// This macro can be used to generate code for each peripheral instance of the SPI master driver. diff --git a/esp-metadata-generated/src/_generated_esp32s3.rs b/esp-metadata-generated/src/_generated_esp32s3.rs index 1a309abeaef..e64a6ccd98b 100644 --- a/esp-metadata-generated/src/_generated_esp32s3.rs +++ b/esp-metadata-generated/src/_generated_esp32s3.rs @@ -156,6 +156,15 @@ macro_rules! property { ("timergroup.timg_has_timer1") => { true }; + ("timergroup.timg_has_divcnt_rst") => { + false + }; + ("uart.ram_size") => { + 128 + }; + ("uart.ram_size", str) => { + stringify!(128) + }; ("wifi.has_wifi6") => { false }; @@ -210,17 +219,18 @@ macro_rules! for_each_i2c_master { /// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum. /// - `$rx`, `$tx`, `$cts`, `$rts`: signal names. /// -/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)` +/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR)` #[macro_export] #[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))] macro_rules! for_each_uart { ($($pattern:tt => $code:tt;)*) => { macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} } - _for_each_inner!((UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)); - _for_each_inner!((UART1, Uart1, U1RXD, U1TXD, U1CTS, U1RTS)); - _for_each_inner!((UART2, Uart2, U2RXD, U2TXD, U2CTS, U2RTS)); - _for_each_inner!((all(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS), (UART1, Uart1, - U1RXD, U1TXD, U1CTS, U1RTS), (UART2, Uart2, U2RXD, U2TXD, U2CTS, U2RTS))); + _for_each_inner!((UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR)); + _for_each_inner!((UART1, Uart1, U1RXD, U1TXD, U1CTS, U1RTS, U1DTR)); + _for_each_inner!((UART2, Uart2, U2RXD, U2TXD, U2CTS, U2RTS, U2DTR)); + _for_each_inner!((all(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR), (UART1, + Uart1, U1RXD, U1TXD, U1CTS, U1RTS, U1DTR), (UART2, Uart2, U2RXD, U2TXD, U2CTS, + U2RTS, U2DTR))); }; } /// This macro can be used to generate code for each peripheral instance of the SPI master driver. diff --git a/esp-metadata/CHANGELOG.md b/esp-metadata/CHANGELOG.md index 23907e65b5c..1767bc30d88 100644 --- a/esp-metadata/CHANGELOG.md +++ b/esp-metadata/CHANGELOG.md @@ -9,7 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Added `Config::generate_metadata` to generate code for firmware crates. (#3604) ### Changed @@ -17,6 +16,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +### Removed + + +## [v0.8.0] - 2025-07-16 + +### Added + +- Added `Config::generate_metadata` to generate code for firmware crates. (#3604) + ### Removed - Removed the firmware-side component of the crate. (#3604) @@ -69,4 +77,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [0.6.0]: https://github.com/esp-rs/esp-hal/releases/tag/esp-metadata-v0.6.0 [v0.7.0]: https://github.com/esp-rs/esp-hal/compare/esp-metadata-v0.6.0...esp-metadata-v0.7.0 -[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-metadata-v0.7.0...HEAD +[v0.8.0]: https://github.com/esp-rs/esp-hal/compare/esp-metadata-v0.7.0...esp-metadata-v0.8.0 +[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-metadata-v0.8.0...HEAD diff --git a/esp-metadata/Cargo.toml b/esp-metadata/Cargo.toml index 8a4dce21f5c..d78bc6fcb93 100644 --- a/esp-metadata/Cargo.toml +++ b/esp-metadata/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "esp-metadata" -version = "0.7.0" +version = "0.8.0" edition = "2024" rust-version = "1.86.0" description = "Metadata for Espressif devices" diff --git a/esp-metadata/devices/esp32.toml b/esp-metadata/devices/esp32.toml index c42411b887b..db39efdbcb1 100644 --- a/esp-metadata/devices/esp32.toml +++ b/esp-metadata/devices/esp32.toml @@ -598,15 +598,17 @@ instances = [ [device.timergroup] timg_has_timer1 = true +timg_has_divcnt_rst = false instances = [{ name = "timg0" }, { name = "timg1" }] [device.uart] support_status = "supported" instances = [ - { name = "uart0", sys_instance = "Uart0", tx = "U0TXD", rx = "U0RXD", cts = "U0CTS", rts = "U0RTS" }, - { name = "uart1", sys_instance = "Uart1", tx = "U1TXD", rx = "U1RXD", cts = "U1CTS", rts = "U1RTS" }, - { name = "uart2", sys_instance = "Uart2", tx = "U2TXD", rx = "U2RXD", cts = "U2CTS", rts = "U2RTS" }, + { name = "uart0", sys_instance = "Uart0", tx = "U0TXD", rx = "U0RXD", cts = "U0CTS", rts = "U0RTS", dtr = "U0DTR" }, + { name = "uart1", sys_instance = "Uart1", tx = "U1TXD", rx = "U1RXD", cts = "U1CTS", rts = "U1RTS", dtr = "U1DTR" }, + { name = "uart2", sys_instance = "Uart2", tx = "U2TXD", rx = "U2RXD", cts = "U2CTS", rts = "U2RTS", dtr = "U2DTR" }, ] +ram_size = 128 [device.ethernet] support_status = "not_supported" diff --git a/esp-metadata/devices/esp32c2.toml b/esp-metadata/devices/esp32c2.toml index 01e87524f50..688bb468b45 100644 --- a/esp-metadata/devices/esp32c2.toml +++ b/esp-metadata/devices/esp32c2.toml @@ -254,13 +254,15 @@ instances = [ [device.timergroup] instances = [{ name = "timg0" }] +timg_has_divcnt_rst = true [device.uart] support_status = "supported" instances = [ - { name = "uart0", sys_instance = "Uart0", tx = "U0TXD", rx = "U0RXD", cts = "U0CTS", rts = "U0RTS" }, - { name = "uart1", sys_instance = "Uart1", tx = "U1TXD", rx = "U1RXD", cts = "U1CTS", rts = "U1RTS" }, + { name = "uart0", sys_instance = "Uart0", tx = "U0TXD", rx = "U0RXD", cts = "U0CTS", rts = "U0RTS", dtr = "U0DTR" }, + { name = "uart1", sys_instance = "Uart1", tx = "U1TXD", rx = "U1RXD", cts = "U1CTS", rts = "U1RTS", dtr = "U1DTR" }, ] +ram_size = 128 # Other drivers which are partially supported but have no other configuration: diff --git a/esp-metadata/devices/esp32c3.toml b/esp-metadata/devices/esp32c3.toml index 25af3c87bb0..05bb474304f 100644 --- a/esp-metadata/devices/esp32c3.toml +++ b/esp-metadata/devices/esp32c3.toml @@ -300,13 +300,15 @@ instances = [ [device.timergroup] instances = [{ name = "timg0" }, { name = "timg1" }] +timg_has_divcnt_rst = true [device.uart] support_status = "supported" instances = [ - { name = "uart0", sys_instance = "Uart0", tx = "U0TXD", rx = "U0RXD", cts = "U0CTS", rts = "U0RTS" }, - { name = "uart1", sys_instance = "Uart1", tx = "U1TXD", rx = "U1RXD", cts = "U1CTS", rts = "U1RTS" }, + { name = "uart0", sys_instance = "Uart0", tx = "U0TXD", rx = "U0RXD", cts = "U0CTS", rts = "U0RTS", dtr = "U0DTR" }, + { name = "uart1", sys_instance = "Uart1", tx = "U1TXD", rx = "U1RXD", cts = "U1CTS", rts = "U1RTS", dtr = "U1DTR" }, ] +ram_size = 128 [device.ds] support_status = "not_supported" diff --git a/esp-metadata/devices/esp32c6.toml b/esp-metadata/devices/esp32c6.toml index 81aff6befe3..8eccf05573b 100644 --- a/esp-metadata/devices/esp32c6.toml +++ b/esp-metadata/devices/esp32c6.toml @@ -425,6 +425,10 @@ has_arbitration_en = true has_tx_fifo_watermark = true bus_timeout_is_exponential = true +[device.lp_i2c_master] +support_status = "partial" +fifo_size = 16 + [device.i2c_slave] support_status = "not_supported" @@ -450,13 +454,19 @@ instances = [ [device.timergroup] instances = [{ name = "timg0" }, { name = "timg1" }] +timg_has_divcnt_rst = true [device.uart] support_status = "supported" instances = [ - { name = "uart0", sys_instance = "Uart0", tx = "U0TXD", rx = "U0RXD", cts = "U0CTS", rts = "U0RTS" }, - { name = "uart1", sys_instance = "Uart1", tx = "U1TXD", rx = "U1RXD", cts = "U1CTS", rts = "U1RTS" }, + { name = "uart0", sys_instance = "Uart0", tx = "U0TXD", rx = "U0RXD", cts = "U0CTS", rts = "U0RTS", dtr = "U0DTR" }, + { name = "uart1", sys_instance = "Uart1", tx = "U1TXD", rx = "U1RXD", cts = "U1CTS", rts = "U1RTS", dtr = "U1DTR" }, ] +ram_size = 128 + +[device.lp_uart] +support_status = "partial" +ram_size = 32 [device.ds] support_status = "not_supported" diff --git a/esp-metadata/devices/esp32h2.toml b/esp-metadata/devices/esp32h2.toml index a28fd2144e7..85bd4019349 100644 --- a/esp-metadata/devices/esp32h2.toml +++ b/esp-metadata/devices/esp32h2.toml @@ -371,13 +371,15 @@ instances = [ [device.timergroup] instances = [{ name = "timg0" }, { name = "timg1" }] +timg_has_divcnt_rst = true [device.uart] support_status = "supported" instances = [ - { name = "uart0", sys_instance = "Uart0", tx = "U0TXD", rx = "U0RXD", cts = "U0CTS", rts = "U0RTS" }, - { name = "uart1", sys_instance = "Uart1", tx = "U1TXD", rx = "U1RXD", cts = "U1CTS", rts = "U1RTS" }, + { name = "uart0", sys_instance = "Uart0", tx = "U0TXD", rx = "U0RXD", cts = "U0CTS", rts = "U0RTS", dtr = "U0DTR" }, + { name = "uart1", sys_instance = "Uart1", tx = "U1TXD", rx = "U1RXD", cts = "U1CTS", rts = "U1RTS", dtr = "U1DTR" }, ] +ram_size = 128 [device.ds] support_status = "not_supported" diff --git a/esp-metadata/devices/esp32s2.toml b/esp-metadata/devices/esp32s2.toml index e64b451cbf4..b041d253598 100644 --- a/esp-metadata/devices/esp32s2.toml +++ b/esp-metadata/devices/esp32s2.toml @@ -421,14 +421,16 @@ instances = [ [device.timergroup] timg_has_timer1 = true +timg_has_divcnt_rst = false instances = [{ name = "timg0" }, { name = "timg1" }] [device.uart] support_status = "supported" instances = [ - { name = "uart0", sys_instance = "Uart0", tx = "U0TXD", rx = "U0RXD", cts = "U0CTS", rts = "U0RTS" }, - { name = "uart1", sys_instance = "Uart1", tx = "U1TXD", rx = "U1RXD", cts = "U1CTS", rts = "U1RTS" }, + { name = "uart0", sys_instance = "Uart0", tx = "U0TXD", rx = "U0RXD", cts = "U0CTS", rts = "U0RTS", dtr = "U0DTR" }, + { name = "uart1", sys_instance = "Uart1", tx = "U1TXD", rx = "U1RXD", cts = "U1CTS", rts = "U1RTS", dtr = "U1DTR" }, ] +ram_size = 128 [device.rgb_display] # via SPI and I2S support_status = "not_supported" diff --git a/esp-metadata/devices/esp32s3.toml b/esp-metadata/devices/esp32s3.toml index b3cfd8ec261..db80cfbe73f 100644 --- a/esp-metadata/devices/esp32s3.toml +++ b/esp-metadata/devices/esp32s3.toml @@ -596,15 +596,17 @@ instances = [ [device.timergroup] timg_has_timer1 = true +timg_has_divcnt_rst = false instances = [{ name = "timg0" }, { name = "timg1" }] [device.uart] support_status = "supported" instances = [ - { name = "uart0", sys_instance = "Uart0", tx = "U0TXD", rx = "U0RXD", cts = "U0CTS", rts = "U0RTS" }, - { name = "uart1", sys_instance = "Uart1", tx = "U1TXD", rx = "U1RXD", cts = "U1CTS", rts = "U1RTS" }, - { name = "uart2", sys_instance = "Uart2", tx = "U2TXD", rx = "U2RXD", cts = "U2CTS", rts = "U2RTS" }, + { name = "uart0", sys_instance = "Uart0", tx = "U0TXD", rx = "U0RXD", cts = "U0CTS", rts = "U0RTS", dtr = "U0DTR" }, + { name = "uart1", sys_instance = "Uart1", tx = "U1TXD", rx = "U1RXD", cts = "U1CTS", rts = "U1RTS", dtr = "U1DTR" }, + { name = "uart2", sys_instance = "Uart2", tx = "U2TXD", rx = "U2RXD", cts = "U2CTS", rts = "U2RTS", dtr = "U2DTR" }, ] +ram_size = 128 [device.touch] support_status = "not_supported" diff --git a/esp-metadata/src/cfg.rs b/esp-metadata/src/cfg.rs index 96ae11751c0..c5c4970b342 100644 --- a/esp-metadata/src/cfg.rs +++ b/esp-metadata/src/cfg.rs @@ -329,6 +329,13 @@ driver_configs![ fifo_size: u32, } }, + LpI2cMasterProperties { + driver: lp_i2c_master, + name: "LP I2C master", + properties: { + fifo_size: u32, + } + }, I2cSlaveProperties { driver: i2c_slave, name: "I2C slave", @@ -453,6 +460,8 @@ driver_configs![ properties: { #[serde(default)] timg_has_timer1: bool, + #[serde(default)] + timg_has_divcnt_rst: bool, } }, TouchProperties { @@ -468,7 +477,16 @@ driver_configs![ UartProperties { driver: uart, name: "UART", - properties: {} + properties: { + ram_size: u32, + } + }, + LpUartProperties { + driver: lp_uart, + name: "LP UART", + properties: { + ram_size: u32, + } }, UlpFsmProperties { driver: ulp_fsm, diff --git a/esp-metadata/src/cfg/gpio.rs b/esp-metadata/src/cfg/gpio.rs index cb02bcfa09f..4c850e7ecac 100644 --- a/esp-metadata/src/cfg/gpio.rs +++ b/esp-metadata/src/cfg/gpio.rs @@ -376,24 +376,17 @@ pub(crate) fn generate_gpios(gpio: &super::GpioProperties) -> TokenStream { let io_mux_accessor = if gpio.remap_iomux_pin_registers { let iomux_pin_regs = gpio.pins_and_signals.pins.iter().map(|pin| { let pin = number(pin.pin); - let reg = format_ident!("GPIO{pin}"); let accessor = format_ident!("gpio{pin}"); - quote! { #pin => transmute::<&'static io_mux::#reg, &'static io_mux::GPIO0>(iomux.#accessor()), } + quote! { #pin => iomux.#accessor(), } }); quote! { pub(crate) fn io_mux_reg(gpio_num: u8) -> &'static crate::pac::io_mux::GPIO0 { - use core::mem::transmute; - - use crate::{pac::io_mux, peripherals::IO_MUX}; - - let iomux = IO_MUX::regs(); - unsafe { - match gpio_num { - #(#iomux_pin_regs)* - other => panic!("GPIO {} does not exist", other), - } + let iomux = crate::peripherals::IO_MUX::regs(); + match gpio_num { + #(#iomux_pin_regs)* + other => panic!("GPIO {} does not exist", other), } } diff --git a/esp-metadata/src/cfg/uart.rs b/esp-metadata/src/cfg/uart.rs index 9d60f12db2a..477c450c958 100644 --- a/esp-metadata/src/cfg/uart.rs +++ b/esp-metadata/src/cfg/uart.rs @@ -20,6 +20,9 @@ pub(crate) struct UartInstanceConfig { /// IOMUX signal name of the instance's RTS signal. pub rts: String, + + /// IOMUX signal name of the instance's DTR signal. + pub dtr: String, } /// Generates `for_each_uart!` which can be used to implement the UART @@ -39,11 +42,12 @@ pub(crate) fn generate_uart_peripherals(uart: &UartProperties) -> TokenStream { let tx = format_ident!("{}", instance_config.tx); let cts = format_ident!("{}", instance_config.cts); let rts = format_ident!("{}", instance_config.rts); + let dtr = format_ident!("{}", instance_config.dtr); // The order and meaning of these tokens must match their use in the // `for_each_uart!` call. quote! { - #instance, #sys, #rx, #tx, #cts, #rts + #instance, #sys, #rx, #tx, #cts, #rts, #dtr } }) .collect::>(); @@ -65,7 +69,7 @@ pub(crate) fn generate_uart_peripherals(uart: &UartProperties) -> TokenStream { /// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum. /// - `$rx`, `$tx`, `$cts`, `$rts`: signal names. /// - /// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)` + /// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS, U0DTR)` #for_each } } diff --git a/esp-println/CHANGELOG.md b/esp-println/CHANGELOG.md index 0fc4450447a..1e69cef3081 100644 --- a/esp-println/CHANGELOG.md +++ b/esp-println/CHANGELOG.md @@ -13,6 +13,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +### Fixed + + +### Removed + + +## [v0.15.0] - 2025-07-16 + ### Fixed - Fixed timestamp when using `defmt-espflash` (#3725) @@ -99,4 +107,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [0.13.1]: https://github.com/esp-rs/esp-hal/releases/tag/esp-println-v0.13.1 [v0.14.0]: https://github.com/esp-rs/esp-hal/compare/esp-println-v0.13.1...esp-println-v0.14.0 -[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-println-v0.14.0...HEAD +[v0.15.0]: https://github.com/esp-rs/esp-hal/compare/esp-println-v0.14.0...esp-println-v0.15.0 +[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-println-v0.15.0...HEAD diff --git a/esp-println/Cargo.toml b/esp-println/Cargo.toml index 0fe9aa55aca..bdbbc75c012 100644 --- a/esp-println/Cargo.toml +++ b/esp-println/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "esp-println" -version = "0.14.0" +version = "0.15.0" edition = "2024" rust-version = "1.86.0" description = "Provides `print!` and `println!` implementations various Espressif devices" @@ -32,7 +32,7 @@ defmt = { version = "1.0.1", optional = true } log-04 = { package = "log", version = "0.4.27", optional = true } [build-dependencies] -esp-metadata-generated = { version = "0.0.1", path = "../esp-metadata-generated", features = ["build-script"] } +esp-metadata-generated = { version = "0.1.0", path = "../esp-metadata-generated", features = ["build-script"] } log-04 = { package = "log", version = "0.4.27" } [features] diff --git a/esp-riscv-rt/CHANGELOG.md b/esp-riscv-rt/CHANGELOG.md index 419ba59ccfe..7f135eba083 100644 --- a/esp-riscv-rt/CHANGELOG.md +++ b/esp-riscv-rt/CHANGELOG.md @@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [v0.12.0] - 2025-07-16 + ## [v0.11.0] - 2025-06-03 ### Changed @@ -99,4 +101,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [0.10.0]: https://github.com/esp-rs/esp-hal/releases/tag/esp-riscv-rt-v0.10.0 [v0.11.0]: https://github.com/esp-rs/esp-hal/compare/esp-riscv-rt-v0.10.0...esp-riscv-rt-v0.11.0 -[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-riscv-rt-v0.11.0...HEAD +[v0.12.0]: https://github.com/esp-rs/esp-hal/compare/esp-riscv-rt-v0.11.0...esp-riscv-rt-v0.12.0 +[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-riscv-rt-v0.12.0...HEAD diff --git a/esp-riscv-rt/Cargo.toml b/esp-riscv-rt/Cargo.toml index 165d435cde5..eeacd3c8b8c 100644 --- a/esp-riscv-rt/Cargo.toml +++ b/esp-riscv-rt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "esp-riscv-rt" -version = "0.11.0" +version = "0.12.0" edition = "2024" rust-version = "1.86.0" description = "Minimal runtime / startup for RISC-V CPUs from Espressif" diff --git a/esp-rom-sys/CHANGELOG.md b/esp-rom-sys/CHANGELOG.md index caa9a6eadd9..8387b3d6528 100644 --- a/esp-rom-sys/CHANGELOG.md +++ b/esp-rom-sys/CHANGELOG.md @@ -19,9 +19,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed -## [v0.1.0] - 2025-07-01 +## [v0.1.1] - 2025-07-16 -Initial Release +## [v0.1.0] - 2025-07-01 [v0.1.0]: https://github.com/esp-rs/esp-hal/releases/tag/esp-rom-sys-v0.1.0 -[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-rom-sys-v0.1.0...HEAD +[v0.1.1]: https://github.com/esp-rs/esp-hal/compare/esp-rom-sys-v0.1.0...esp-rom-sys-v0.1.1 +[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-rom-sys-v0.1.1...HEAD diff --git a/esp-rom-sys/Cargo.toml b/esp-rom-sys/Cargo.toml index b5caba75069..3d9472c3185 100644 --- a/esp-rom-sys/Cargo.toml +++ b/esp-rom-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "esp-rom-sys" -version = "0.1.0" +version = "0.1.1" edition = "2024" rust-version = "1.86.0" description = "ROM code support" @@ -27,7 +27,7 @@ document-features = "0.2.11" log-04 = { package = "log", version = "0.4.26", optional = true } [build-dependencies] -esp-metadata-generated = { version = "0.0.1", path = "../esp-metadata-generated", features = ["build-script"] } +esp-metadata-generated = { version = "0.1.0", path = "../esp-metadata-generated", features = ["build-script"] } [features] #! ### Chip selection diff --git a/esp-storage/CHANGELOG.md b/esp-storage/CHANGELOG.md index fa944e8f8d4..ca1dcbb0905 100644 --- a/esp-storage/CHANGELOG.md +++ b/esp-storage/CHANGELOG.md @@ -15,12 +15,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Fix incorrect usage of MaybeUninit (#3677) -- Use `libesp_rom.a` from ESP-IDF on ESP32 as a replacement for our incomplete and less accurate port (#3688) ### Removed +## [v0.7.0] - 2025-07-16 + +### Fixed + +- Fix incorrect usage of MaybeUninit (#3677) +- Use `libesp_rom.a` from ESP-IDF on ESP32 as a replacement for our incomplete and less accurate port (#3688) + ## [v0.6.0] - 2025-06-03 ### Changed @@ -55,4 +60,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [0.5.0]: https://github.com/esp-rs/esp-hal/releases/tag/esp-storage-v0.5.0 [v0.6.0]: https://github.com/esp-rs/esp-hal/compare/esp-storage-v0.5.0...esp-storage-v0.6.0 -[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-storage-v0.6.0...HEAD +[v0.7.0]: https://github.com/esp-rs/esp-hal/compare/esp-storage-v0.6.0...esp-storage-v0.7.0 +[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-storage-v0.7.0...HEAD diff --git a/esp-storage/Cargo.toml b/esp-storage/Cargo.toml index 998ca1368a6..957033ead06 100644 --- a/esp-storage/Cargo.toml +++ b/esp-storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "esp-storage" -version = "0.6.0" +version = "0.7.0" edition = "2024" rust-version = "1.86.0" description = "Implementation of embedded-storage traits to access unencrypted ESP32 flash" @@ -22,7 +22,7 @@ embedded-storage = "0.3.1" # Optional dependencies critical-section = { version = "1.2.0", optional = true } -esp-rom-sys = { version = "0.1.0", path = "../esp-rom-sys", optional = true } +esp-rom-sys = { version = "0.1.1", path = "../esp-rom-sys", optional = true } # Unstable dependencies that are not (strictly) part of the public API diff --git a/esp-wifi/CHANGELOG.md b/esp-wifi/CHANGELOG.md index 94fc92efd93..bea8a977f15 100644 --- a/esp-wifi/CHANGELOG.md +++ b/esp-wifi/CHANGELOG.md @@ -12,10 +12,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- MSRV is now 1.88.0 (#3742) -- Removed `esp_wifi::deinit_unchecked` and `esp_wifi::EspWifiController::deinit` - you can just drop `EspWifiController` instead (#3553) -- `defmt` and `log-04` can no longer be selected at the same time (#3675) -- `esp_wifi::init` no longer requires the `RADIO_CLK` peripheral (#3687) ### Fixed @@ -23,6 +19,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [v0.15.0] - 2025-07-16 + +### Changed + +- MSRV is now 1.88.0 (#3742) +- Removed `esp_wifi::deinit_unchecked` and `esp_wifi::EspWifiController::deinit` - you can just drop `EspWifiController` instead (#3553) +- `defmt` and `log-04` can no longer be selected at the same time (#3675) +- `esp_wifi::init` no longer requires the `RADIO_CLK` peripheral (#3687) + ## [v0.14.1] - 2025-06-05 ### Added @@ -270,4 +275,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [0.13.0]: https://github.com/esp-rs/esp-hal/releases/tag/esp-wifi-v0.13.0 [v0.14.0]: https://github.com/esp-rs/esp-hal/compare/esp-wifi-v0.13.0...esp-wifi-v0.14.0 [v0.14.1]: https://github.com/esp-rs/esp-hal/compare/esp-wifi-v0.14.0...esp-wifi-v0.14.1 -[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-wifi-v0.14.1...HEAD +[v0.15.0]: https://github.com/esp-rs/esp-hal/compare/esp-wifi-v0.14.1...esp-wifi-v0.15.0 +[Unreleased]: https://github.com/esp-rs/esp-hal/compare/esp-wifi-v0.15.0...HEAD diff --git a/esp-wifi/Cargo.toml b/esp-wifi/Cargo.toml index 152e8ca1bf4..e9a4443be07 100644 --- a/esp-wifi/Cargo.toml +++ b/esp-wifi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "esp-wifi" -version = "0.14.1" +version = "0.15.0" edition = "2024" rust-version = "1.88.0" description = "A WiFi, Bluetooth and ESP-NOW driver for use with Espressif chips and bare-metal Rust" @@ -15,7 +15,7 @@ bench = false test = false [dependencies] -esp-hal = { version = "1.0.0-beta.1", path = "../esp-hal", default-features = false, features = ["requires-unstable"] } +esp-hal = { version = "1.0.0-rc.0", path = "../esp-hal", default-features = false, features = ["requires-unstable"] } critical-section = "1.2.0" cfg-if = "1.0.0" portable-atomic = { version = "1.11.0", default-features = false } @@ -30,13 +30,13 @@ rand_core = "0.9.3" allocator-api2 = { version = "0.3.0", default-features = false, features = ["alloc"] } document-features = "0.2.11" esp-alloc = { version = "0.8.0", path = "../esp-alloc", optional = true } -esp-config = { version = "0.4.0", path = "../esp-config" } -esp-metadata-generated = { version = "0.0.1", path = "../esp-metadata-generated" } +esp-config = { version = "0.5.0", path = "../esp-config" } +esp-metadata-generated = { version = "0.1.0", path = "../esp-metadata-generated" } esp-wifi-sys = "0.7.1" num-derive = { version = "0.4.2" } num-traits = { version = "0.2.19", default-features = false } portable_atomic_enum = { version = "0.3.1", features = ["portable-atomic"] } -xtensa-lx-rt = { version = "0.19.0", path = "../xtensa-lx-rt", optional = true } +xtensa-lx-rt = { version = "0.20.0", path = "../xtensa-lx-rt", optional = true } # Optional dependencies enabling ecosystem features serde = { version = "1.0.218", default-features = false, features = ["derive"], optional = true } @@ -52,8 +52,8 @@ defmt = { version = "1.0.1", optional = true } log-04 = { package = "log", version = "0.4.27", optional = true } [build-dependencies] -esp-config = { version = "0.4.0", path = "../esp-config", features = ["build"] } -esp-metadata-generated = { version = "0.0.1", path = "../esp-metadata-generated", features = ["build-script"] } +esp-config = { version = "0.5.0", path = "../esp-config", features = ["build"] } +esp-metadata-generated = { version = "0.1.0", path = "../esp-metadata-generated", features = ["build-script"] } [features] default = ["builtin-scheduler", "esp-alloc"] diff --git a/esp-wifi/MIGRATING-0.14.0.md b/esp-wifi/MIGRATING-0.14.0.md index f80b4eb24df..3b121c32b68 100644 --- a/esp-wifi/MIGRATING-0.14.0.md +++ b/esp-wifi/MIGRATING-0.14.0.md @@ -1,4 +1,4 @@ -# Migration Guide from 0.14.0 to {{currentVersion}} +# Migration Guide from 0.14.0 to 0.15.0 ## Deinitialization diff --git a/esp-wifi/src/preempt_builtin/preempt_riscv.rs b/esp-wifi/src/preempt_builtin/preempt_riscv.rs index 85b2d1d0c40..ea3c8638fbf 100644 --- a/esp-wifi/src/preempt_builtin/preempt_riscv.rs +++ b/esp-wifi/src/preempt_builtin/preempt_riscv.rs @@ -1,7 +1,7 @@ +pub use esp_hal::trapframe::TrapFrame; use esp_wifi_sys::c_types; use super::*; -pub use crate::hal::interrupt::TrapFrame; pub(crate) fn new_task_context( task: extern "C" fn(*mut c_types::c_void), diff --git a/esp-wifi/src/preempt_builtin/timer/riscv.rs b/esp-wifi/src/preempt_builtin/timer/riscv.rs index cb58ce11237..e3c75e1b860 100644 --- a/esp-wifi/src/preempt_builtin/timer/riscv.rs +++ b/esp-wifi/src/preempt_builtin/timer/riscv.rs @@ -39,14 +39,14 @@ pub(crate) fn disable_multitasking() { extern "C" fn FROM_CPU_INTR2(trap_frame: &mut TrapFrame) { // clear FROM_CPU_INTR3 SystemPeripheral::regs() - .cpu_intr_from_cpu_2() - .modify(|_, w| w.cpu_intr_from_cpu_2().clear_bit()); + .cpu_intr_from_cpu(2) + .modify(|_, w| w.cpu_intr().clear_bit()); task_switch(trap_frame); } pub(crate) fn yield_task() { SystemPeripheral::regs() - .cpu_intr_from_cpu_2() - .modify(|_, w| w.cpu_intr_from_cpu_2().set_bit()); + .cpu_intr_from_cpu(2) + .modify(|_, w| w.cpu_intr().set_bit()); } diff --git a/esp-wifi/src/radio/radio_esp32c6.rs b/esp-wifi/src/radio/radio_esp32c6.rs index eb523480ac7..90421ecc97b 100644 --- a/esp-wifi/src/radio/radio_esp32c6.rs +++ b/esp-wifi/src/radio/radio_esp32c6.rs @@ -1,21 +1,18 @@ +use crate::hal::peripherals::{INTERRUPT_CORE0, Interrupt}; #[cfg(any(feature = "wifi", feature = "ble"))] #[allow(unused_imports)] -use crate::{ - binary, - hal::{interrupt, peripherals::Interrupt}, -}; +use crate::{binary, hal::interrupt}; pub(crate) fn setup_radio_isr() { - use crate::hal::peripherals::INTERRUPT_CORE0; // make sure to disable WIFI_BB/MODEM_PERI_TIMEOUT by mapping it to CPU // interrupt 31 which is masked by default for some reason for this // interrupt, mapping it to 0 doesn't deactivate it INTERRUPT_CORE0::regs() - .wifi_bb_intr_map() - .write(|w| unsafe { w.wifi_bb_intr_map().bits(31) }); + .core_0_intr_map(Interrupt::WIFI_BB as usize) + .write(|w| unsafe { w.bits(31) }); INTERRUPT_CORE0::regs() - .modem_peri_timeout_intr_map() - .write(|w| unsafe { w.modem_peri_timeout_intr_map().bits(31) }); + .core_0_intr_map(Interrupt::MODEM_PERI_TIMEOUT as usize) + .write(|w| unsafe { w.bits(31) }); } pub(crate) fn shutdown_radio_isr() { diff --git a/hil-test/tests/init.rs b/hil-test/tests/init.rs index a3b8220a827..d25f70ed9bf 100644 --- a/hil-test/tests/init.rs +++ b/hil-test/tests/init.rs @@ -44,6 +44,20 @@ mod tests { } } + #[test] + #[cfg(timergroup_timg0)] + fn test_wdt0_uses_prescaler() { + esp_hal::init( + Config::default().with_watchdog( + WatchdogConfig::default() + .with_timg0(WatchdogStatus::Enabled(Duration::from_micros(53_687_092))), // multiplied by 80 (for the default clock source), then taking the 32 lower bits this is 0x40 + ), + ); + + let delay = Delay::new(); + delay.delay(Duration::from_millis(250)); + } + #[test] #[cfg(timergroup_timg1)] fn test_feeding_timg1_wdt() { diff --git a/hil-test/tests/interrupt.rs b/hil-test/tests/interrupt.rs index 482b9dd91c0..215617fec6b 100644 --- a/hil-test/tests/interrupt.rs +++ b/hil-test/tests/interrupt.rs @@ -79,7 +79,7 @@ mod tests { } } - let sw0_trigger_addr = cpu_intr.register_block().cpu_intr_from_cpu_0() as *const _ as u32; + let sw0_trigger_addr = cpu_intr.register_block().cpu_intr_from_cpu(0) as *const _ as u32; critical_section::with(|cs| { SWINT0 diff --git a/xtask/src/commands/release/bump_version.rs b/xtask/src/commands/release/bump_version.rs index 981d12c18e7..d420018a3b4 100644 --- a/xtask/src/commands/release/bump_version.rs +++ b/xtask/src/commands/release/bump_version.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; use strum::IntoEnumIterator; use toml_edit::{Item, TableLike, Value}; -use crate::{cargo::CargoToml, changelog::Changelog, commands::PLACEHOLDER, Package, Version}; +use crate::{Package, Version, cargo::CargoToml, changelog::Changelog, commands::PLACEHOLDER}; #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] pub enum VersionBump { @@ -65,18 +65,6 @@ pub fn update_package( version: &VersionBump, dry_run: bool, ) -> Result { - let version = { - if package.package() == Package::EspRomSys && version != &VersionBump::Patch { - log::warn!( - "Bump '{:?}' is not acceptable for package esp-rom-sys - using 'Patch'", - version - ); - &VersionBump::Patch - } else { - version - } - }; - check_crate_before_bumping(package)?; let new_version = bump_crate_version(package, version, dry_run)?; finalize_changelog(package, &new_version, dry_run)?; @@ -229,6 +217,7 @@ fn bump_crate_version( pub fn do_version_bump(version: &semver::Version, amount: &VersionBump) -> Result { fn bump_version_number(version: &mut semver::Version, amount: &VersionBump) { + log::info!("Bumping version number: {version} by {amount:?}"); match amount { VersionBump::Major => { version.major += 1; @@ -261,15 +250,11 @@ pub fn do_version_bump(version: &semver::Version, amount: &VersionBump) -> Resul if let Some(pre_version) = version.pre.as_str().strip_prefix(&format!("{pre}.")) { let pre_version = pre_version.parse::()?; version.pre = Prerelease::new(&format!("{pre}.{}", pre_version + 1)).unwrap(); - } else if version.pre.as_str().is_empty() { - // Start a new pre-release - bump_version_number(&mut version, &amount); - version.pre = Prerelease::new(&format!("{pre}.0")).unwrap(); } else { - bail!( - "Unexpected pre-release version format found: {}", - version.pre.as_str() - ); + // if the pre version is _not_ the same as the one we had, it's a new pre-release + // use the new pre and reset the bump to 0 + // equally, if the version is not a pre-release, we need to append the pre-release + version.pre = Prerelease::new(&format!("{pre}.0")).unwrap(); } } } @@ -371,21 +356,6 @@ mod test { ("0.1.0", VersionBump::Patch, "0.1.1"), ("0.1.0", VersionBump::Minor, "0.2.0"), ("0.1.0", VersionBump::Major, "1.0.0"), - ( - "0.1.0", - VersionBump::PreRelease("alpha".to_string()), - "0.1.1-alpha.0", - ), - ( - "0.1.0", - VersionBump::PreRelease("alpha".to_string()), - "0.2.0-alpha.0", - ), - ( - "0.1.0", - VersionBump::PreRelease("alpha".to_string()), - "1.0.0-alpha.0", - ), // amount is ignored, assuming same release cycle ("0.1.0-beta.0", VersionBump::Minor, "0.1.0"), ("0.1.0-beta.0", VersionBump::Major, "0.1.0"), @@ -399,6 +369,11 @@ mod test { VersionBump::PreRelease("beta".to_string()), "0.1.0-beta.1", ), + ( + "0.1.0-beta.0", + VersionBump::PreRelease("rc".to_string()), + "0.1.0-rc.0", + ), ]; for (version, amount, expected) in test_cases { diff --git a/xtask/src/commands/release/execute_plan.rs b/xtask/src/commands/release/execute_plan.rs index 0ba39e7b976..b9bd558b533 100644 --- a/xtask/src/commands/release/execute_plan.rs +++ b/xtask/src/commands/release/execute_plan.rs @@ -17,6 +17,10 @@ pub struct ApplyPlanArgs { /// update code. #[arg(long)] no_dry_run: bool, + + /// Instead of opening the pull request, just print base URL and body. + #[arg(long)] + manual_pull_request: bool, } pub fn execute_plan(workspace: &Path, args: ApplyPlanArgs) -> Result<()> { @@ -100,7 +104,7 @@ pub fn execute_plan(workspace: &Path, args: ApplyPlanArgs) -> Result<()> { let branch = make_git_changes(!args.no_dry_run, "release-branch", "Finalize crate releases")?; - open_pull_request(&branch, !args.no_dry_run, &plan_source, &plan) + open_pull_request(&branch, !args.no_dry_run, args.manual_pull_request, &plan_source, &plan) .with_context(|| "Failed to open pull request")?; if !args.no_dry_run { @@ -191,6 +195,7 @@ pub(crate) fn make_git_changes(dry_run: bool, branch_name: &str, commit: &str) - fn open_pull_request( branch: &Branch, dry_run: bool, + manual_pull_request: bool, release_plan_str: &str, release_plan: &Plan, ) -> Result<()> { @@ -246,7 +251,7 @@ cargo xrelease publish-plan --no-dry-run ); // https://stackoverflow.com/a/64565317 - if open_pr_url.len() > 8201 { + if manual_pull_request || open_pr_url.len() > 8201 { println!(); println!("PR description begins here."); println!(); diff --git a/xtask/src/commands/release/plan.rs b/xtask/src/commands/release/plan.rs index b50f23a6597..2f216be39f1 100644 --- a/xtask/src/commands/release/plan.rs +++ b/xtask/src/commands/release/plan.rs @@ -120,6 +120,20 @@ pub fn plan(workspace: &Path, args: PlanArgs) -> Result<()> { } else { ReleaseType::Minor }; + + // Special case: some packages are perma-unstable, meaning they won't ever have a stable + // release. For these packages, we always use a patch release. + let amount = match package { + Package::EspRomSys if amount != ReleaseType::Patch => { + log::debug!( + "Bump '{:?}' is not acceptable for package esp-rom-sys - using 'Patch'", + amount + ); + ReleaseType::Patch + } + _ => amount, + }; + log::debug!("{} needs {:?} version bump", package, amount); Some(amount) } else { diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 912738c94e2..9e80bfe438f 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs @@ -179,6 +179,7 @@ impl Package { Package::EspConfig => features.push("build".to_owned()), Package::EspHal => { features.push("unstable".to_owned()); + features.push("rt".to_owned()); if config.contains("psram") { // TODO this doesn't test octal psram (since `ESP_HAL_CONFIG_PSRAM_MODE` // defaults to `quad`) as it would require a separate build @@ -193,6 +194,7 @@ impl Package { } Package::EspWifi => { features.push("esp-hal/unstable".to_owned()); + features.push("esp-hal/rt".to_owned()); features.push("defmt".to_owned()); if config.contains("wifi") { features.push("wifi".to_owned()); @@ -213,12 +215,14 @@ impl Package { } Package::EspHalEmbassy => { features.push("esp-hal/unstable".to_owned()); + features.push("esp-hal/rt".to_owned()); features.push("defmt".to_owned()); features.push("executors".to_owned()); } Package::EspIeee802154 => { features.push("defmt".to_owned()); features.push("esp-hal/unstable".to_owned()); + features.push("esp-hal/rt".to_owned()); } Package::EspLpHal => { if config.contains("lp_core") { @@ -251,12 +255,19 @@ impl Package { match self { Package::EspHal => { - // Make sure no additional features (e.g. no "unstable") still compiles: + // This checks if the `esp-hal` crate compiles with the no features (other than the + // chip selection) + + // This tests that disabling the `rt` feature works cases.push(vec![]); + // This checks if the `esp-hal` crate compiles _without_ the `unstable` feature + // enabled + cases.push(vec!["rt".to_owned()]); } Package::EspWifi => { // Minimal set of features that when enabled _should_ still compile: cases.push(vec![ + "esp-hal/rt".to_owned(), "esp-hal/unstable".to_owned(), "builtin-scheduler".to_owned(), ]); @@ -525,12 +536,23 @@ pub fn format_package(workspace: &Path, package: Package, check: bool) -> Result Ok(()) } -pub fn update_metadata(workspace: &Path) -> Result<()> { +pub fn update_metadata(workspace: &Path, check: bool) -> Result<()> { update_chip_support_table(workspace)?; generate_metadata(workspace, save)?; format_package(workspace, Package::EspMetadataGenerated, false)?; + if check { + let res = std::process::Command::new("git") + .args(["diff", "HEAD", "esp-metadata-generated"]) + .output()?; + if !res.stdout.is_empty() { + return Err(anyhow::Error::msg( + "detected `esp-metadata-generated` changes. Run `cargo xtask update-metadata`, and commit the changes.", + )); + } + } + Ok(()) } diff --git a/xtask/src/main.rs b/xtask/src/main.rs index fc7ab277d8d..b1a1d1d9afc 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -43,7 +43,7 @@ enum Cli { /// Check the changelog for packages. CheckChangelog(CheckChangelogArgs), /// Re-generate metadata and the chip support table in the esp-hal README. - UpdateMetadata, + UpdateMetadata(UpdateMetadataArgs), } #[derive(Debug, Args)] @@ -105,6 +105,13 @@ struct CheckChangelogArgs { normalize: bool, } +#[derive(Debug, Args)] +struct UpdateMetadataArgs { + /// Run in 'check' mode; exists with 0 if formatted correctly, 1 otherwise + #[arg(long)] + check: bool, +} + // ---------------------------------------------------------------------------- // Application @@ -164,7 +171,7 @@ fn main() -> Result<()> { Cli::LintPackages(args) => lint_packages(&workspace, args), Cli::SemverCheck(args) => semver_checks(&workspace, args), Cli::CheckChangelog(args) => check_changelog(&workspace, &args.packages, args.normalize), - Cli::UpdateMetadata => xtask::update_metadata(&workspace), + Cli::UpdateMetadata(args) => xtask::update_metadata(&workspace, args.check), } } @@ -279,7 +286,9 @@ fn lint_package( builder = builder.arg(arg.to_string()); } - builder = builder.arg(format!("--features={}", features.join(","))); + if !features.is_empty() { + builder = builder.arg(format!("--features={}", features.join(","))); + } let builder = if fix { builder.arg("--fix").arg("--lib").arg("--allow-dirty") diff --git a/xtensa-lx-rt-proc-macros/Cargo.toml b/xtensa-lx-rt-proc-macros/Cargo.toml index 4560c7cbf7d..8f5e42218ce 100644 --- a/xtensa-lx-rt-proc-macros/Cargo.toml +++ b/xtensa-lx-rt-proc-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xtensa-lx-rt-proc-macros" -version = "0.3.0" +version = "0.4.0" edition = "2024" rust-version = "1.86.0" description = "Attributes re-exported in `xtensa-lx-rt`" diff --git a/xtensa-lx-rt/CHANGELOG.md b/xtensa-lx-rt/CHANGELOG.md index c60b1dc9f58..f4bc8951cd0 100644 --- a/xtensa-lx-rt/CHANGELOG.md +++ b/xtensa-lx-rt/CHANGELOG.md @@ -12,11 +12,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- MSRV is now 1.88.0 (#3742) ### Fixed +### Removed + + +## [v0.20.0] - 2025-07-16 + +### Changed + +- MSRV is now 1.88.0 (#3742) + ### Removed - The `esp32`, `esp32s2` and `esp32s3` features have been removed. (#3598) @@ -53,4 +61,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [0.18.0]: https://github.com/esp-rs/esp-hal/releases/tag/xtensa-lx-rt-v0.18.0 [v0.19.0]: https://github.com/esp-rs/esp-hal/compare/xtensa-lx-rt-v0.18.0...xtensa-lx-rt-v0.19.0 -[Unreleased]: https://github.com/esp-rs/esp-hal/compare/xtensa-lx-rt-v0.19.0...HEAD +[v0.20.0]: https://github.com/esp-rs/esp-hal/compare/xtensa-lx-rt-v0.19.0...xtensa-lx-rt-v0.20.0 +[Unreleased]: https://github.com/esp-rs/esp-hal/compare/xtensa-lx-rt-v0.20.0...HEAD diff --git a/xtensa-lx-rt/Cargo.toml b/xtensa-lx-rt/Cargo.toml index f383d322c10..1893360eaed 100644 --- a/xtensa-lx-rt/Cargo.toml +++ b/xtensa-lx-rt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xtensa-lx-rt" -version = "0.19.0" +version = "0.20.0" edition = "2024" rust-version = "1.88.0" description = "Minimal startup/runtime for Xtensa LX CPUs" @@ -17,9 +17,9 @@ test = false [dependencies] document-features = "0.2.11" -macros = { version = "0.3.0", package = "xtensa-lx-rt-proc-macros", path = "../xtensa-lx-rt-proc-macros" } +macros = { version = "0.4.0", package = "xtensa-lx-rt-proc-macros", path = "../xtensa-lx-rt-proc-macros" } r0 = "1.0.0" -xtensa-lx = { version = "0.11.0", path = "../xtensa-lx" } +xtensa-lx = { version = "0.12.0", path = "../xtensa-lx" } [build-dependencies] diff --git a/xtensa-lx/CHANGELOG.md b/xtensa-lx/CHANGELOG.md index 8d3f5fdebda..5a81b80fd07 100644 --- a/xtensa-lx/CHANGELOG.md +++ b/xtensa-lx/CHANGELOG.md @@ -19,6 +19,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [v0.12.0] - 2025-07-16 + +### Changed + +* This crate no longer uses the `links` field in its `Cargo.toml` (#3697) + ## [v0.11.0] - 2025-06-03 ### Changed @@ -57,4 +63,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [0.10.0]: https://github.com/esp-rs/esp-hal/releases/tag/xtensa-lx-v0.10.0 [v0.11.0]: https://github.com/esp-rs/esp-hal/compare/xtensa-lx-v0.10.0...xtensa-lx-v0.11.0 -[Unreleased]: https://github.com/esp-rs/esp-hal/compare/xtensa-lx-v0.11.0...HEAD +[v0.12.0]: https://github.com/esp-rs/esp-hal/compare/xtensa-lx-v0.11.0...xtensa-lx-v0.12.0 +[Unreleased]: https://github.com/esp-rs/esp-hal/compare/xtensa-lx-v0.12.0...HEAD diff --git a/xtensa-lx/Cargo.toml b/xtensa-lx/Cargo.toml index 96dbec44e86..8b7c87b4c53 100644 --- a/xtensa-lx/Cargo.toml +++ b/xtensa-lx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xtensa-lx" -version = "0.11.0" +version = "0.12.0" edition = "2024" rust-version = "1.86.0" description = "Low-level access to Xtensa LX processors and peripherals"