mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-26 20:00:32 +00:00
Combine the esp-ulp-riscv-hal
and esp32c6-lp-hal
packages (#1115)
* Combine `esp-ulp-riscv-hal` and `esp32c6-lp-hal` into a single package * Update LP core examples * Update CI workflow * Fix `LP_UART` example
This commit is contained in:
parent
f52aa1351c
commit
9bf70ff792
141
.github/workflows/ci.yml
vendored
141
.github/workflows/ci.yml
vendored
@ -65,6 +65,34 @@ jobs:
|
||||
- name: rustdoc
|
||||
run: cd esp-hal-smartled/ && cargo doc -Zbuild-std=core --target=riscv32imc-unknown-none-elf --features=esp32c3
|
||||
|
||||
esp-lp-hal:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@v1
|
||||
with:
|
||||
target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf
|
||||
toolchain: nightly
|
||||
components: rust-src
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
# Perform a full build initially to verify that the examples not only
|
||||
# build, but also link successfully.
|
||||
- name: build esp-lp-hal (esp32c6)
|
||||
run: cd esp-lp-hal/ && cargo build --release --target=riscv32imac-unknown-none-elf --features=esp32c6 --examples
|
||||
- name: build esp-lp-hal (esp32s2)
|
||||
run: cd esp-lp-hal/ && cargo build --release --target=riscv32imc-unknown-none-elf --features=esp32s2 --examples
|
||||
- name: build esp-lp-hal (esp32s3)
|
||||
run: cd esp-lp-hal/ && cargo build --release --target=riscv32imc-unknown-none-elf --features=esp32s3 --examples
|
||||
# Ensure documentation can be built
|
||||
- name: rustdoc
|
||||
run: |
|
||||
cd esp-lp-hal/
|
||||
cargo doc --features=esp32c6
|
||||
cargo doc --features=esp32s2
|
||||
cargo doc --features=esp32s3
|
||||
|
||||
esp-riscv-rt:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@ -89,28 +117,6 @@ jobs:
|
||||
- name: rustdoc
|
||||
run: cd esp-riscv-rt/ && cargo doc
|
||||
|
||||
esp-ulp-riscv-hal:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@v1
|
||||
with:
|
||||
target: riscv32imc-unknown-none-elf
|
||||
toolchain: nightly
|
||||
components: rust-src
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
# Perform a full build initially to verify that the examples not only
|
||||
# build, but also link successfully.
|
||||
- name: build esp-ulp-riscv-hal (esp32s2)
|
||||
run: cd esp-ulp-riscv-hal/ && cargo build --release --features=esp32s2 --examples
|
||||
- name: build esp-ulp-riscv-hal (esp32s3)
|
||||
run: cd esp-ulp-riscv-hal/ && cargo build --release --features=esp32s3 --examples
|
||||
# Ensure documentation can be built
|
||||
- name: rustdoc
|
||||
run: cd esp-ulp-riscv-hal/ && cargo doc --features=esp32s3
|
||||
|
||||
esp32-hal:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@ -290,10 +296,12 @@ jobs:
|
||||
components: rust-src
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
# build the lp-hal examples first to make sure the examples which expect
|
||||
# the ELF files to be present will compile
|
||||
- name: build esp32c6-lp-hal prerequisites
|
||||
run: cd esp32c6-lp-hal/ && cargo +nightly build --release --examples
|
||||
# Build the `esp-lp-hal` examples first to make sure the examples which
|
||||
# expect these ELF files to be present will compile.
|
||||
- name: build prerequisites
|
||||
run: |
|
||||
cd esp-lp-hal/
|
||||
cargo build --release --features=esp32c6 --target=riscv32imac-unknown-none-elf --examples
|
||||
|
||||
# Perform a full build initially to verify that the examples not only
|
||||
# build, but also link successfully.
|
||||
@ -346,26 +354,6 @@ jobs:
|
||||
- name: rustdoc
|
||||
run: cd esp32c6-hal/ && cargo doc --features=eh1
|
||||
|
||||
esp32c6-lp-hal:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@v1
|
||||
with:
|
||||
target: riscv32imac-unknown-none-elf
|
||||
toolchain: nightly
|
||||
components: rust-src
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
# Perform a full build initially to verify that the examples not only
|
||||
# build, but also link successfully.
|
||||
- name: build esp32c6-lp-hal (no features)
|
||||
run: cd esp32c6-lp-hal/ && cargo +nightly build --release --examples
|
||||
# Ensure documentation can be built
|
||||
- name: rustdoc
|
||||
run: cd esp32c6-lp-hal/ && cargo doc
|
||||
|
||||
esp32h2-hal:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@ -478,10 +466,12 @@ jobs:
|
||||
components: rust-src
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
# build the esp-ulp-riscv-hal examples first to make sure the examples which expect
|
||||
# the ELF files to be present will compile
|
||||
- name: build esp-ulp-riscv-hal prerequisites
|
||||
run: cd esp-ulp-riscv-hal/ && cargo +nightly build --release --features=esp32s2 --examples
|
||||
# Build the `esp-lp-hal` examples first to make sure the examples which
|
||||
# expect these ELF files to be present will compile.
|
||||
- name: build prerequisites
|
||||
run: |
|
||||
cd esp-lp-hal/
|
||||
cargo +nightly build --release --features=esp32s2 --target=riscv32imc-unknown-none-elf --examples
|
||||
|
||||
# Perform a full build initially to verify that the examples not only
|
||||
# build, but also link successfully.
|
||||
@ -494,9 +484,6 @@ jobs:
|
||||
cd esp32s2-hal/
|
||||
cargo +esp build --examples --features=eh1,ufmt,log
|
||||
cargo +esp build --examples --features=eh1,ufmt,defmt
|
||||
# FIXME: `time-systick` feature disabled for now, see 'esp32s2-hal/Cargo.toml'.
|
||||
# - name: check esp32s2-hal (async, systick)
|
||||
# run: cd esp32s2-hal/ && cargo check --example=embassy_hello_world --features=embassy,embassy-time-systick,executor
|
||||
- name: check esp32s2-hal (embassy, timg0)
|
||||
run: |
|
||||
cd esp32s2-hal/
|
||||
@ -556,10 +543,12 @@ jobs:
|
||||
components: rust-src
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
# build the esp-ulp-riscv-hal examples first to make sure the examples which expect
|
||||
# the ELF files to be present will compile
|
||||
- name: build esp-ulp-riscv-hal prerequisites
|
||||
run: cd esp-ulp-riscv-hal/ && cargo +nightly build --release --features=esp32s3 --examples
|
||||
# Build the `esp-lp-hal` examples first to make sure the examples which
|
||||
# expect these ELF files to be present will compile.
|
||||
- name: build prerequisites
|
||||
run: |
|
||||
cd esp-lp-hal/
|
||||
cargo build --release --features=esp32s3 --target=riscv32imc-unknown-none-elf --examples
|
||||
|
||||
# Perform a full build initially to verify that the examples not only
|
||||
# build, but also link successfully.
|
||||
@ -641,12 +630,13 @@ jobs:
|
||||
components: rust-src
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
# Build the esp32c6-lp-hal examples first. This is done to ensure the
|
||||
# examples which expect the ELF files to be present will compile:
|
||||
- name: build esp32c6-lp-hal prerequisites
|
||||
run: cd esp32c6-lp-hal && cargo build --release --examples
|
||||
|
||||
# Verify the MSRV for all RISC-V chips.
|
||||
- name: msrv (esp-lp-hal)
|
||||
run: |
|
||||
cd esp-lp-hal/
|
||||
cargo build --features=esp32c6 --target=riscv32imac-unknown-none-elf
|
||||
cargo build --features=esp32s2 --target=riscv32imc-unknown-none-elf
|
||||
cargo build --features=esp32s3 --target=riscv32imc-unknown-none-elf
|
||||
- name: msrv (esp32c2-hal)
|
||||
run: |
|
||||
cd esp32c2-hal/
|
||||
@ -662,10 +652,6 @@ jobs:
|
||||
cd esp32c6-hal/
|
||||
cargo build --features=eh1,ufmt,log
|
||||
cargo build --features=defmt
|
||||
- name: msrv (esp32c6-lp-hal)
|
||||
run: |
|
||||
cd esp32c6-lp-hal/
|
||||
cargo build
|
||||
- name: msrv (esp32h2-hal)
|
||||
run: |
|
||||
cd esp32h2-hal/
|
||||
@ -695,11 +681,6 @@ jobs:
|
||||
version: ${{ env.MSRV }}
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
# Build the `esp-ulp-riscv-hal` examples first. This is done to ensure
|
||||
# the examples which expect the ELF files to be present will compile:
|
||||
- name: build esp-ulp-riscv-hal prerequisites
|
||||
run: cd esp-ulp-riscv-hal && cargo build --release --features=esp32s3 --examples
|
||||
|
||||
# Verify the MSRV for all Xtensa chips:
|
||||
- name: msrv (esp32-hal)
|
||||
run: |
|
||||
@ -733,20 +714,20 @@ jobs:
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
# Run 'cargo clippy' on all packages targeting RISC-V:
|
||||
- name: clippy (esp-lp-hal, esp32c6)
|
||||
run: cd esp-lp-hal && cargo clippy --features=esp32c6 -- -D warnings
|
||||
- name: clippy (esp-lp-hal, esp32s2)
|
||||
run: cd esp-lp-hal && cargo clippy --features=esp32s2 -- -D warnings
|
||||
- name: clippy (esp-lp-hal, esp32s3)
|
||||
run: cd esp-lp-hal && cargo clippy --features=esp32s3 -- -D warnings
|
||||
- name: clippy (esp-riscv-rt)
|
||||
run: cd esp-riscv-rt && cargo clippy --target=riscv32imc-unknown-none-elf -- -D warnings
|
||||
- name: clippy (esp-ulp-riscv-hal, esp32s2)
|
||||
run: cd esp-ulp-riscv-hal && cargo clippy --features=esp32s2 -- -D warnings
|
||||
- name: clippy (esp-ulp-riscv-hal, esp32s3)
|
||||
run: cd esp-ulp-riscv-hal && cargo clippy --features=esp32s3 -- -D warnings
|
||||
- name: clippy (esp32c2-hal)
|
||||
run: cd esp32c2-hal && cargo clippy -- -D warnings
|
||||
- name: clippy (esp32c3-hal)
|
||||
run: cd esp32c3-hal && cargo clippy -- -D warnings
|
||||
- name: clippy (esp32c6-hal)
|
||||
run: cd esp32c6-hal && cargo clippy -- -D warnings
|
||||
- name: clippy (esp32c6-lp-hal)
|
||||
run: cd esp32c6-lp-hal && cargo clippy -- -D warnings
|
||||
- name: clippy (esp32h2-hal)
|
||||
run: cd esp32h2-hal && cargo clippy -- -D warnings
|
||||
- name: clippy (esp32p4-hal)
|
||||
@ -790,10 +771,10 @@ jobs:
|
||||
run: cargo fmt --all --manifest-path=esp-hal-procmacros/Cargo.toml -- --check
|
||||
- name: rustfmt (esp-hal-smartled)
|
||||
run: cargo fmt --all --manifest-path=esp-hal-smartled/Cargo.toml -- --check
|
||||
- name: rustfmt (esp-lp-hal)
|
||||
run: cargo fmt --all --manifest-path=esp-lp-hal/Cargo.toml -- --check
|
||||
- name: rustfmt (esp-riscv-rt)
|
||||
run: cargo fmt --all --manifest-path=esp-riscv-rt/Cargo.toml -- --check
|
||||
- name: rustfmt (esp-ulp-riscv-hal)
|
||||
run: cargo fmt --all --manifest-path=esp-ulp-riscv-hal/Cargo.toml -- --check
|
||||
- name: rustfmt (esp32-hal)
|
||||
run: cargo fmt --all --manifest-path=esp32-hal/Cargo.toml -- --check
|
||||
- name: rustfmt (esp32c2-hal)
|
||||
@ -802,8 +783,6 @@ jobs:
|
||||
run: cargo fmt --all --manifest-path=esp32c3-hal/Cargo.toml -- --check
|
||||
- name: rustfmt (esp32c6-hal)
|
||||
run: cargo fmt --all --manifest-path=esp32c6-hal/Cargo.toml -- --check
|
||||
- name: rustfmt (esp32c6-lp-hal)
|
||||
run: cargo fmt --all --manifest-path=esp32c6-lp-hal/Cargo.toml -- --check
|
||||
- name: rustfmt (esp32h2-hal)
|
||||
run: cargo fmt --all --manifest-path=esp32h2-hal/Cargo.toml -- --check
|
||||
- name: rustfmt (esp32p4-hal)
|
||||
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -12,11 +12,11 @@
|
||||
// Uncomment ONE line for the chip you want to work on.
|
||||
// This makes rust-analyzer work on the HAL crate and all its dependencies.
|
||||
"rust-analyzer.linkedProjects": [
|
||||
// "esp-lp-hal/Cargo.toml"
|
||||
"esp32-hal/Cargo.toml"
|
||||
// "esp32c2-hal/Cargo.toml"
|
||||
// "esp32c3-hal/Cargo.toml"
|
||||
// "esp32c6-hal/Cargo.toml"
|
||||
// "esp32c6-lp-hal/Cargo.toml"
|
||||
// "esp32h2-hal/Cargo.toml"
|
||||
// "esp32p4-hal/Cargo.toml"
|
||||
// "esp32s2-hal/Cargo.toml"
|
||||
|
@ -108,6 +108,12 @@ fn get_hal_crate() -> (
|
||||
use proc_macro_crate::crate_name;
|
||||
|
||||
// Package name:
|
||||
#[cfg(any(
|
||||
feature = "esp32c6-lp",
|
||||
feature = "esp32s2-ulp",
|
||||
feature = "esp32s3-ulp"
|
||||
))]
|
||||
let hal_crate = crate_name("esp-lp-hal");
|
||||
#[cfg(feature = "esp32")]
|
||||
let hal_crate = crate_name("esp32-hal");
|
||||
#[cfg(feature = "esp32c2")]
|
||||
@ -116,22 +122,22 @@ fn get_hal_crate() -> (
|
||||
let hal_crate = crate_name("esp32c3-hal");
|
||||
#[cfg(feature = "esp32c6")]
|
||||
let hal_crate = crate_name("esp32c6-hal");
|
||||
#[cfg(feature = "esp32c6-lp")]
|
||||
let hal_crate = crate_name("esp32c6-lp-hal");
|
||||
#[cfg(feature = "esp32h2")]
|
||||
let hal_crate = crate_name("esp32h2-hal");
|
||||
#[cfg(feature = "esp32p4")]
|
||||
let hal_crate = crate_name("esp32p4-hal");
|
||||
#[cfg(feature = "esp32s2")]
|
||||
let hal_crate = crate_name("esp32s2-hal");
|
||||
#[cfg(feature = "esp32s2-ulp")]
|
||||
let hal_crate = crate_name("esp-ulp-riscv-hal");
|
||||
#[cfg(feature = "esp32s3")]
|
||||
let hal_crate = crate_name("esp32s3-hal");
|
||||
#[cfg(feature = "esp32s3-ulp")]
|
||||
let hal_crate = crate_name("esp-ulp-riscv-hal");
|
||||
|
||||
// Crate name:
|
||||
#[cfg(any(
|
||||
feature = "esp32c6-lp",
|
||||
feature = "esp32s2-ulp",
|
||||
feature = "esp32s3-ulp"
|
||||
))]
|
||||
let hal_crate_name = Ident::new("esp_lp_hal", Span::call_site().into());
|
||||
#[cfg(feature = "esp32")]
|
||||
let hal_crate_name = Ident::new("esp32_hal", Span::call_site().into());
|
||||
#[cfg(feature = "esp32c2")]
|
||||
@ -140,20 +146,14 @@ fn get_hal_crate() -> (
|
||||
let hal_crate_name = Ident::new("esp32c3_hal", Span::call_site().into());
|
||||
#[cfg(feature = "esp32c6")]
|
||||
let hal_crate_name = Ident::new("esp32c6_hal", Span::call_site().into());
|
||||
#[cfg(feature = "esp32c6-lp")]
|
||||
let hal_crate_name = Ident::new("esp32c6_lp_hal", Span::call_site().into());
|
||||
#[cfg(feature = "esp32h2")]
|
||||
let hal_crate_name = Ident::new("esp32h2_hal", Span::call_site().into());
|
||||
#[cfg(feature = "esp32p4")]
|
||||
let hal_crate_name = Ident::new("esp32p4_hal", Span::call_site().into());
|
||||
#[cfg(feature = "esp32s2")]
|
||||
let hal_crate_name = Ident::new("esp32s2_hal", Span::call_site().into());
|
||||
#[cfg(feature = "esp32s2-ulp")]
|
||||
let hal_crate_name = Ident::new("esp_ulp_riscv_hal", Span::call_site().into());
|
||||
#[cfg(feature = "esp32s3")]
|
||||
let hal_crate_name = Ident::new("esp32s3_hal", Span::call_site().into());
|
||||
#[cfg(feature = "esp32s3-ulp")]
|
||||
let hal_crate_name = Ident::new("esp_ulp_riscv_hal", Span::call_site().into());
|
||||
|
||||
(hal_crate, hal_crate_name)
|
||||
}
|
||||
@ -679,18 +679,9 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
|
||||
use self::lp_core::{extract_pin, get_simplename, make_magic_symbol_name};
|
||||
|
||||
#[cfg(feature = "esp32c6-lp")]
|
||||
let found_crate =
|
||||
crate_name("esp32c6-lp-hal").expect("esp32c6_lp_hal is present in `Cargo.toml`");
|
||||
#[cfg(any(feature = "esp32s2-ulp", feature = "esp32s3-ulp"))]
|
||||
let found_crate =
|
||||
crate_name("esp-ulp-riscv-hal").expect("esp-ulp-riscv-hal is present in `Cargo.toml`");
|
||||
|
||||
let found_crate = crate_name("esp-lp-hal").expect("esp-lp-hal is present in `Cargo.toml`");
|
||||
let hal_crate = match found_crate {
|
||||
#[cfg(feature = "esp32c6-lp")]
|
||||
FoundCrate::Itself => quote!(esp32c6_lp_hal),
|
||||
#[cfg(any(feature = "esp32s2-ulp", feature = "esp32s3-ulp"))]
|
||||
FoundCrate::Itself => quote!(esp_ulp_riscv_hal),
|
||||
FoundCrate::Itself => quote!(esp_lp_hal),
|
||||
FoundCrate::Name(name) => {
|
||||
let ident = Ident::new(&name, Span::call_site());
|
||||
quote!( #ident::Something )
|
||||
@ -729,12 +720,12 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
}
|
||||
used_pins.push(pin);
|
||||
create_peripheral.push(quote!(
|
||||
let mut #param_name = unsafe { the_hal::gpio::conjour().unwrap() };
|
||||
let mut #param_name = unsafe { the_hal::gpio::conjure().unwrap() };
|
||||
));
|
||||
}
|
||||
"LpUart" => {
|
||||
create_peripheral.push(quote!(
|
||||
let mut #param_name = unsafe { the_hal::uart::conjour().unwrap() };
|
||||
let mut #param_name = unsafe { the_hal::uart::conjure().unwrap() };
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
@ -772,6 +763,7 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
|
||||
main(#(#param_names),*);
|
||||
}
|
||||
|
||||
#f
|
||||
)
|
||||
.into()
|
||||
|
12
esp-lp-hal/.cargo/config.toml
Normal file
12
esp-lp-hal/.cargo/config.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[build]
|
||||
# target = "riscv32imc-unknown-none-elf" # ESP32-S2 + ESP32-S3
|
||||
target = "riscv32imac-unknown-none-elf" # ESP32-C6
|
||||
|
||||
[target.'cfg(target_arch = "riscv32")']
|
||||
runner = "espflash flash --monitor"
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
]
|
||||
|
||||
[unstable]
|
||||
build-std = ["core"]
|
@ -12,12 +12,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Add the `esp32c6-lp-hal` package (#714)
|
||||
- Add GPIO (output) and delay functionality to `esp32c6-lp-hal` (#715)
|
||||
- Add GPIO input support and implement additional `embedded-hal` output traits for the C6's LP core [#720]
|
||||
- Add the `ulp-riscv-hal` package (#840)
|
||||
- Add LP_UART basic driver (#1113)
|
||||
|
||||
### Changed
|
||||
|
||||
- Renamed to `esp-ulp-riscv-hal` (#916)
|
||||
|
||||
### Fixed
|
||||
|
||||
### Removed
|
||||
|
||||
[Unreleased]: https://github.com/esp-rs/esp-hal/commits/main/esp32c6-lp-hal
|
||||
[Unreleased]: https://github.com/esp-rs/esp-hal/commits/main/esp-lp-hal
|
64
esp-lp-hal/Cargo.toml
Normal file
64
esp-lp-hal/Cargo.toml
Normal file
@ -0,0 +1,64 @@
|
||||
[package]
|
||||
name = "esp-lp-hal"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.67.0"
|
||||
description = "HAL for low-power RISC-V coprocessors found in ESP32 devices"
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
keywords = [
|
||||
"embedded",
|
||||
"embedded-hal",
|
||||
"esp",
|
||||
"esp32",
|
||||
"no-std",
|
||||
]
|
||||
categories = [
|
||||
"embedded",
|
||||
"hardware-support",
|
||||
"no-std",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "1.0.0"
|
||||
embedded-hal-02 = { version = "0.2.7", package = "embedded-hal", optional = true, features = ["unproven"] }
|
||||
embedded-hal-1 = { version = "1.0.0", package = "embedded-hal", optional = true }
|
||||
esp32c6-lp = { version = "0.1.0", features = ["critical-section"], optional = true }
|
||||
esp32s2-ulp = { version = "0.1.0", features = ["critical-section"], optional = true }
|
||||
esp32s3-ulp = { version = "0.1.0", features = ["critical-section"], optional = true }
|
||||
nb = { version = "1.1.0", optional = true }
|
||||
paste = { version = "1.0.14", optional = true }
|
||||
procmacros = { package = "esp-hal-procmacros", path = "../esp-hal-procmacros" }
|
||||
riscv = { version = "0.11.0", features = ["critical-section-single-hart"] }
|
||||
|
||||
[dev-dependencies]
|
||||
panic-halt = "0.2.0"
|
||||
|
||||
[features]
|
||||
default = ["embedded-hal-02"]
|
||||
|
||||
embedded-hal-02 = ["dep:embedded-hal-02"]
|
||||
embedded-hal-1 = ["dep:embedded-hal-1"]
|
||||
|
||||
esp32c6 = ["dep:esp32c6-lp", "procmacros/esp32c6-lp", "dep:nb", "dep:paste"]
|
||||
esp32s2 = ["dep:esp32s2-ulp", "procmacros/esp32s2-ulp"]
|
||||
esp32s3 = ["dep:esp32s3-ulp", "procmacros/esp32s3-ulp"]
|
||||
|
||||
debug = [
|
||||
"esp32c6-lp?/impl-register-debug",
|
||||
"esp32s2-ulp?/impl-register-debug",
|
||||
"esp32s3-ulp?/impl-register-debug",
|
||||
]
|
||||
|
||||
[[example]]
|
||||
name = "blinky"
|
||||
required-features = ["embedded-hal-02"]
|
||||
|
||||
[[example]]
|
||||
name = "uart"
|
||||
required-features = ["embedded-hal-02", "esp32c6"]
|
||||
|
||||
[patch.crates-io]
|
||||
esp32s2-ulp = { git = "https://github.com/esp-rs/esp-pacs", rev = "bcab40a" }
|
||||
esp32s3-ulp = { git = "https://github.com/esp-rs/esp-pacs", rev = "bcab40a" }
|
73
esp-lp-hal/README.md
Normal file
73
esp-lp-hal/README.md
Normal file
@ -0,0 +1,73 @@
|
||||
# esp-lp-hal
|
||||
|
||||
[](https://crates.io/crates/esp-lp-hal)
|
||||
[](https://docs.rs/esp-lp-hal)
|
||||

|
||||
[](https://matrix.to/#/#esp-rs:matrix.org)
|
||||
|
||||
`no_std` HAL for the low-power RISC-V coprocessors found on the ESP32-C6, ESP32-S2, and ESP32-S3 from Espressif.
|
||||
|
||||
Implements a number of the traits defined in [embedded-hal](https://github.com/rust-embedded/embedded-hal).
|
||||
|
||||
These devices uses the RISC-V ISA, which is officially supported by the Rust compiler via the `riscv32imc-unknown-none-elf` and `riscv32imac-unknown-none-elf` targets.
|
||||
|
||||
Please refer to the documentation for more information.
|
||||
|
||||
[c6-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf
|
||||
[s2-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf
|
||||
[s3-datasheet]: https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf
|
||||
[c6-trm]: https://www.espressif.com/sites/default/files/documentation/esp32-c6_technical_reference_manual_en.pdf
|
||||
[s2-trm]: https://www.espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf
|
||||
[s3-trm]: https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf
|
||||
|
||||
## [Documentation]
|
||||
|
||||
[documentation]: https://docs.rs/esp-lp-hal/
|
||||
|
||||
## Supported Devices
|
||||
|
||||
| Chip | Datasheet | Technical Reference Manual | Target |
|
||||
| :------: | :----------------------: | :------------------------: | :----------------------------: |
|
||||
| ESP32-C6 | [ESP32-C6][c6-datasheet] | [ESP32-C6][c6-trm] | `riscv32imac-unknown-none-elf` |
|
||||
| ESP32-S2 | [ESP32-S2][s2-datasheet] | [ESP32-S2][s2-trm] | `riscv32imc-unknown-none-elf` |
|
||||
| ESP32-S3 | [ESP32-S3][s3-datasheet] | [ESP32-S3][s3-trm] | `riscv32imc-unknown-none-elf` |
|
||||
|
||||
## Resources
|
||||
|
||||
- [The Rust Programming Language](https://doc.rust-lang.org/book/)
|
||||
- [The Embedded Rust Book](https://docs.rust-embedded.org/book/index.html)
|
||||
- [The Rust on ESP Book](https://esp-rs.github.io/book/)
|
||||
- Datasheets:
|
||||
- [ESP32-C6](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf)
|
||||
- [ESP32-S2](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf)
|
||||
- [ESP32-S3](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf)
|
||||
- Technical Reference Manuals:
|
||||
- [ESP32-C6](https://www.espressif.com/sites/default/files/documentation/esp32-c6_technical_reference_manual_en.pdf)
|
||||
- [ESP32-S2](https://www.espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf)
|
||||
- [ESP32-S3](https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf)
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Installing the Rust Compiler Targets
|
||||
|
||||
The compilation targets for these devices are officially supported by the mainline Rust compiler and can be installed using [rustup](https://rustup.rs/):
|
||||
|
||||
```shell
|
||||
rustup target add riscv32imc-unknown-none-elf
|
||||
rustup target add riscv32imac-unknown-none-elf
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of:
|
||||
|
||||
- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in
|
||||
the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without
|
||||
any additional terms or conditions.
|
75
esp-lp-hal/build.rs
Normal file
75
esp-lp-hal/build.rs
Normal file
@ -0,0 +1,75 @@
|
||||
use std::{env, error::Error, fs, path::PathBuf};
|
||||
|
||||
// Macros taken from:
|
||||
// https://github.com/TheDan64/inkwell/blob/36c3b10/src/lib.rs#L81-L110
|
||||
|
||||
// Given some features, assert that AT MOST one of the features is enabled.
|
||||
macro_rules! assert_unique_features {
|
||||
() => {};
|
||||
|
||||
( $first:tt $(,$rest:tt)* ) => {
|
||||
$(
|
||||
#[cfg(all(feature = $first, feature = $rest))]
|
||||
compile_error!(concat!("Features \"", $first, "\" and \"", $rest, "\" cannot be used together"));
|
||||
)*
|
||||
assert_unique_features!($($rest),*);
|
||||
};
|
||||
}
|
||||
|
||||
// Given some features, assert that AT LEAST one of the features is enabled.
|
||||
macro_rules! assert_used_features {
|
||||
( $all:tt ) => {
|
||||
#[cfg(not(feature = $all))]
|
||||
compile_error!(concat!("The feature flag must be provided: ", $all));
|
||||
};
|
||||
|
||||
( $($all:tt),+ ) => {
|
||||
#[cfg(not(any($(feature = $all),*)))]
|
||||
compile_error!(concat!("One of the feature flags must be provided: ", $($all, ", "),*));
|
||||
};
|
||||
}
|
||||
|
||||
// Given some features, assert that EXACTLY one of the features is enabled.
|
||||
macro_rules! assert_unique_used_features {
|
||||
( $($all:tt),* ) => {
|
||||
assert_unique_features!($($all),*);
|
||||
assert_used_features!($($all),*);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
// 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
|
||||
};
|
||||
|
||||
// Define all necessary configuration symbols for the configured device:
|
||||
println!("cargo:rustc-cfg={}", device_name);
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// Done!
|
||||
Ok(())
|
||||
}
|
47
esp-lp-hal/examples/blinky.rs
Normal file
47
esp-lp-hal/examples/blinky.rs
Normal file
@ -0,0 +1,47 @@
|
||||
//! Counts a 32 bit value at a known point in memory, and blink GPIO1.
|
||||
//!
|
||||
//! When using the ESP32-C6's LP core, this address in memory is `0x5000_2000`.
|
||||
//!
|
||||
//! When using the ESP32-S2 or ESP32-S3's ULP core, this address in memory is
|
||||
//! `0x5000_0400` (but is `0x400`` from the ULP's point of view!).
|
||||
//!
|
||||
//! Make sure the LP RAM is cleared before loading the code.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use embedded_hal_02::{blocking::delay::DelayMs, digital::v2::OutputPin};
|
||||
use esp_lp_hal::{
|
||||
delay::Delay,
|
||||
gpio::{GpioPin, Output, PushPull},
|
||||
prelude::*,
|
||||
};
|
||||
use panic_halt as _;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "esp32c6")] {
|
||||
const ADDRESS: u32 = 0x5000_2000;
|
||||
} else if #[cfg(any(feature = "esp32s2", feature = "esp32s3"))] {
|
||||
const ADDRESS: u32 = 0x400;
|
||||
}
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main(mut gpio1: GpioPin<Output<PushPull>, 1>) -> ! {
|
||||
let mut i: u32 = 0;
|
||||
|
||||
let ptr = ADDRESS as *mut u32;
|
||||
|
||||
loop {
|
||||
i = i.wrapping_add(1u32);
|
||||
unsafe {
|
||||
ptr.write_volatile(i);
|
||||
}
|
||||
|
||||
gpio1.set_high().unwrap();
|
||||
Delay.delay_ms(500);
|
||||
|
||||
gpio1.set_low().unwrap();
|
||||
Delay.delay_ms(500);
|
||||
}
|
||||
}
|
@ -8,16 +8,14 @@
|
||||
|
||||
use core::fmt::Write;
|
||||
|
||||
use esp32c6_lp_hal::{delay::Delay, prelude::*, uart::LpUart};
|
||||
use embedded_hal_02::blocking::delay::DelayMs;
|
||||
use esp_lp_hal::{delay::Delay, prelude::*, uart::LpUart};
|
||||
use panic_halt as _;
|
||||
|
||||
#[entry]
|
||||
fn main(mut uart: LpUart) -> ! {
|
||||
let _peripherals = esp32c6_lp::Peripherals::take().unwrap();
|
||||
|
||||
let mut delay = Delay::new();
|
||||
loop {
|
||||
writeln!(uart, "Hello World from LP Core").unwrap();
|
||||
delay.delay_ms(1500);
|
||||
Delay.delay_ms(1000);
|
||||
}
|
||||
}
|
@ -6,21 +6,23 @@
|
||||
|
||||
ENTRY(reset_vector)
|
||||
|
||||
VECTOR_TABLE_LENGTH = 0x80;
|
||||
CONFIG_ULP_COPROC_RESERVE_MEM = 1024 * 16;
|
||||
CONFIG_ULP_SHARED_MEM = 0;
|
||||
RAM_LENGTH = CONFIG_ULP_COPROC_RESERVE_MEM - VECTOR_TABLE_LENGTH - CONFIG_ULP_SHARED_MEM;
|
||||
|
||||
MEMORY
|
||||
{
|
||||
/*first 128byte for exception/interrupt vectors*/
|
||||
vector_table(RX) : ORIGIN = 0x50000000, LENGTH = 0x80
|
||||
ram(RWX) : ORIGIN = 0x50000080, LENGTH = CONFIG_ULP_COPROC_RESERVE_MEM - 0x80 - CONFIG_ULP_SHARED_MEM
|
||||
vector_table(RX) : ORIGIN = 0x50000000, LENGTH = VECTOR_TABLE_LENGTH
|
||||
ram(RWX) : ORIGIN = 0x50000080, LENGTH = RAM_LENGTH
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.vector.text :
|
||||
{
|
||||
/*exception/interrupt vectors*/
|
||||
/* Exception/interrupt vectors */
|
||||
__mtvec_base = .;
|
||||
KEEP (*(.init.vector))
|
||||
__mtvec_end = .;
|
@ -3,7 +3,6 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
|
||||
ENTRY(reset_vector)
|
||||
|
||||
@ -17,6 +16,7 @@ MEMORY
|
||||
SECTIONS
|
||||
{
|
||||
. = ORIGIN(ram);
|
||||
|
||||
.text :
|
||||
{
|
||||
*(.text.vectors) /* Default reset vector must link to offset 0x0 */
|
80
esp-lp-hal/src/delay.rs
Normal file
80
esp-lp-hal/src/delay.rs
Normal file
@ -0,0 +1,80 @@
|
||||
//! Simple blocking delay functionality.
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Delay;
|
||||
|
||||
impl Delay {
|
||||
/// Delay for at least the number of specific microseconds.
|
||||
pub fn delay_micros(&mut self, mut us: u32) {
|
||||
const NANOS_PER_MICRO: u32 = 1_000;
|
||||
const MAX_MICROS: u32 = u32::MAX / NANOS_PER_MICRO;
|
||||
|
||||
// Avoid potential overflow if micro -> nano conversion is too large
|
||||
while us > MAX_MICROS {
|
||||
us -= MAX_MICROS;
|
||||
self.delay_nanos(MAX_MICROS * NANOS_PER_MICRO);
|
||||
}
|
||||
|
||||
self.delay_nanos(us * NANOS_PER_MICRO);
|
||||
}
|
||||
|
||||
/// Delay for at least the number of specific nanoseconds.
|
||||
pub fn delay_nanos(&mut self, ns: u32) {
|
||||
let ticks_seconds = unsafe { crate::CPU_CLOCK };
|
||||
let clock = (ns as u64 * (ticks_seconds as u64)) / 1_000_000_000u64;
|
||||
let t0 = cycles();
|
||||
|
||||
while cycles().wrapping_sub(t0) <= clock {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "esp32c6")]
|
||||
#[inline(always)]
|
||||
fn cycles() -> u64 {
|
||||
riscv::register::mcycle::read64()
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
|
||||
#[inline(always)]
|
||||
fn cycles() -> u64 {
|
||||
let mut cycles: u32;
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"rdcycle {cycles}",
|
||||
cycles = out(reg) cycles,
|
||||
)
|
||||
}
|
||||
|
||||
cycles as u64
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-02")]
|
||||
impl embedded_hal_02::blocking::delay::DelayUs<u64> for Delay {
|
||||
#[inline(always)]
|
||||
fn delay_us(&mut self, us: u64) {
|
||||
self.delay_micros(us as u32);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-02")]
|
||||
impl embedded_hal_02::blocking::delay::DelayUs<u32> for Delay {
|
||||
#[inline(always)]
|
||||
fn delay_us(&mut self, us: u32) {
|
||||
self.delay_micros(us);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-02")]
|
||||
impl embedded_hal_02::blocking::delay::DelayMs<u32> for Delay {
|
||||
#[inline(always)]
|
||||
fn delay_ms(&mut self, ms: u32) {
|
||||
self.delay_micros(ms * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-1")]
|
||||
impl embedded_hal_1::delay::DelayNs for Delay {
|
||||
fn delay_ns(&mut self, ns: u32) {
|
||||
self.delay_nanos(ns);
|
||||
}
|
||||
}
|
157
esp-lp-hal/src/gpio.rs
Normal file
157
esp-lp-hal/src/gpio.rs
Normal file
@ -0,0 +1,157 @@
|
||||
//! Low-power GPIO driver
|
||||
//!
|
||||
//! It's assumed that GPIOs are already configured correctly by the HP core.
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[cfg(feature = "esp32c6")]
|
||||
type LpIo = crate::pac::LP_IO;
|
||||
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
|
||||
type LpIo = crate::pac::RTC_IO;
|
||||
|
||||
pub struct Unknown {}
|
||||
|
||||
pub struct Input<MODE> {
|
||||
_mode: PhantomData<MODE>,
|
||||
}
|
||||
|
||||
pub struct Floating;
|
||||
|
||||
pub struct PullDown;
|
||||
|
||||
pub struct PullUp;
|
||||
|
||||
pub struct Output<MODE> {
|
||||
_mode: PhantomData<MODE>,
|
||||
}
|
||||
|
||||
pub struct PushPull;
|
||||
|
||||
pub struct GpioPin<MODE, const PIN: u8> {
|
||||
phantom: PhantomData<MODE>,
|
||||
}
|
||||
|
||||
impl<MODE, const PIN: u8> GpioPin<Input<MODE>, PIN> {
|
||||
pub fn input_state(&self) -> bool {
|
||||
unsafe { &*LpIo::PTR }.in_().read().bits() >> PIN & 0x1 != 0
|
||||
}
|
||||
}
|
||||
|
||||
impl<MODE, const PIN: u8> GpioPin<Output<MODE>, PIN> {
|
||||
pub fn output_state(&self) -> bool {
|
||||
unsafe { &*LpIo::PTR }.out().read().bits() >> PIN & 0x1 != 0
|
||||
}
|
||||
|
||||
pub fn set_output(&mut self, on: bool) {
|
||||
if on {
|
||||
unsafe { &*LpIo::PTR }
|
||||
.out_w1ts()
|
||||
.write(|w| w.out_data_w1ts().variant(1 << PIN));
|
||||
} else {
|
||||
unsafe { &*LpIo::PTR }
|
||||
.out_w1tc()
|
||||
.write(|w| w.out_data_w1tc().variant(1 << PIN));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Used by the `entry` procmacro:
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn conjure<MODE, const PIN: u8>() -> Option<GpioPin<MODE, PIN>> {
|
||||
if PIN > 7 {
|
||||
None
|
||||
} else {
|
||||
Some(GpioPin {
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-02")]
|
||||
impl<MODE, const PIN: u8> embedded_hal_02::digital::v2::InputPin for GpioPin<Input<MODE>, PIN> {
|
||||
type Error = core::convert::Infallible;
|
||||
|
||||
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.input_state())
|
||||
}
|
||||
|
||||
fn is_low(&self) -> Result<bool, Self::Error> {
|
||||
Ok(!self.is_high()?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-02")]
|
||||
impl<MODE, const PIN: u8> embedded_hal_02::digital::v2::OutputPin for GpioPin<Output<MODE>, PIN> {
|
||||
type Error = core::convert::Infallible;
|
||||
|
||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||
self.set_output(false);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||
self.set_output(true);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-02")]
|
||||
impl<MODE, const PIN: u8> embedded_hal_02::digital::v2::StatefulOutputPin
|
||||
for GpioPin<Output<MODE>, PIN>
|
||||
{
|
||||
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.output_state())
|
||||
}
|
||||
|
||||
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
||||
Ok(!self.is_set_high()?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-02")]
|
||||
impl<MODE, const PIN: u8> embedded_hal_02::digital::v2::toggleable::Default
|
||||
for GpioPin<Output<MODE>, PIN>
|
||||
{
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-1")]
|
||||
impl<MODE, const PIN: u8> embedded_hal_1::digital::ErrorType for GpioPin<MODE, PIN> {
|
||||
type Error = core::convert::Infallible;
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-1")]
|
||||
impl<MODE, const PIN: u8> embedded_hal_1::digital::InputPin for GpioPin<Input<MODE>, PIN> {
|
||||
fn is_high(&mut self) -> Result<bool, Self::Error> {
|
||||
Ok(self.input_state())
|
||||
}
|
||||
|
||||
fn is_low(&mut self) -> Result<bool, Self::Error> {
|
||||
Ok(!self.is_high()?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-1")]
|
||||
impl<MODE, const PIN: u8> embedded_hal_1::digital::OutputPin for GpioPin<Output<MODE>, PIN> {
|
||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||
self.set_output(false);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||
self.set_output(true);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-1")]
|
||||
impl<MODE, const PIN: u8> embedded_hal_1::digital::StatefulOutputPin
|
||||
for GpioPin<Output<MODE>, PIN>
|
||||
{
|
||||
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
|
||||
Ok(self.output_state())
|
||||
}
|
||||
|
||||
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
|
||||
Ok(!self.is_set_high()?)
|
||||
}
|
||||
}
|
150
esp-lp-hal/src/lib.rs
Normal file
150
esp-lp-hal/src/lib.rs
Normal file
@ -0,0 +1,150 @@
|
||||
#![allow(asm_sub_register)]
|
||||
#![no_std]
|
||||
|
||||
use core::arch::global_asm;
|
||||
|
||||
pub mod delay;
|
||||
pub mod gpio;
|
||||
#[cfg(esp32c6)]
|
||||
pub mod uart;
|
||||
|
||||
pub mod pac {
|
||||
#[cfg(feature = "esp32c6")]
|
||||
pub use esp32c6_lp::*;
|
||||
#[cfg(feature = "esp32s2")]
|
||||
pub use esp32s2_ulp::*;
|
||||
#[cfg(feature = "esp32s3")]
|
||||
pub use esp32s3_ulp::*;
|
||||
}
|
||||
|
||||
pub mod prelude {
|
||||
pub use procmacros::entry;
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "esp32c6")] {
|
||||
// LP_FAST_CLK is not very accurate, for now use a rough estimate
|
||||
const LP_FAST_CLK_HZ: u32 = 16_000_000;
|
||||
const XTAL_D2_CLK_HZ: u32 = 20_000_000;
|
||||
} else if #[cfg(feature = "esp32s2")] {
|
||||
const LP_FAST_CLK_HZ: u32 = 8_000_000;
|
||||
} else if #[cfg(feature = "esp32s3")] {
|
||||
const LP_FAST_CLK_HZ: u32 = 17_500_000;
|
||||
}
|
||||
}
|
||||
|
||||
pub static mut CPU_CLOCK: u32 = LP_FAST_CLK_HZ;
|
||||
|
||||
#[cfg(feature = "esp32c6")]
|
||||
global_asm!(
|
||||
r#"
|
||||
.section .init.vector, "ax"
|
||||
/* This is the vector table. It is currently empty, but will be populated
|
||||
* with exception and interrupt handlers when this is supported
|
||||
*/
|
||||
|
||||
.align 0x4, 0xff
|
||||
.global _vector_table
|
||||
.type _vector_table, @function
|
||||
_vector_table:
|
||||
.option push
|
||||
.option norvc
|
||||
|
||||
.rept 32
|
||||
nop
|
||||
.endr
|
||||
|
||||
.option pop
|
||||
.size _vector_table, .-_vector_table
|
||||
|
||||
.section .init, "ax"
|
||||
.global reset_vector
|
||||
|
||||
/* The reset vector, jumps to startup code */
|
||||
reset_vector:
|
||||
j __start
|
||||
|
||||
__start:
|
||||
/* setup the stack pointer */
|
||||
la sp, __stack_top
|
||||
call rust_main
|
||||
loop:
|
||||
j loop
|
||||
"#
|
||||
);
|
||||
|
||||
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
|
||||
global_asm!(
|
||||
r#"
|
||||
.section .text.vectors
|
||||
.global irq_vector
|
||||
.global reset_vector
|
||||
|
||||
/* The reset vector, jumps to startup code */
|
||||
reset_vector:
|
||||
j __start
|
||||
|
||||
/* Interrupt handler */
|
||||
.balign 16
|
||||
irq_vector:
|
||||
ret
|
||||
|
||||
.section .text
|
||||
|
||||
__start:
|
||||
/* setup the stack pointer */
|
||||
la sp, __stack_top
|
||||
|
||||
call ulp_riscv_rescue_from_monitor
|
||||
call rust_main
|
||||
call ulp_riscv_halt
|
||||
loop:
|
||||
j loop
|
||||
"#
|
||||
);
|
||||
|
||||
#[link_section = ".init.rust"]
|
||||
#[export_name = "rust_main"]
|
||||
unsafe extern "C" fn lp_core_startup() -> ! {
|
||||
extern "Rust" {
|
||||
fn main() -> !;
|
||||
}
|
||||
|
||||
#[cfg(feature = "esp32c6")]
|
||||
if (*pac::LP_CLKRST::PTR)
|
||||
.lp_clk_conf()
|
||||
.read()
|
||||
.fast_clk_sel()
|
||||
.bit_is_set()
|
||||
{
|
||||
CPU_CLOCK = XTAL_D2_CLK_HZ;
|
||||
}
|
||||
|
||||
main();
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
|
||||
#[link_section = ".init.rust"]
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn ulp_riscv_rescue_from_monitor() {
|
||||
// Rescue RISC-V core from monitor state.
|
||||
unsafe { &*pac::RTC_CNTL::PTR }
|
||||
.cocpu_ctrl()
|
||||
.modify(|_, w| w.cocpu_done().clear_bit().cocpu_shut_reset_en().clear_bit());
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
|
||||
#[link_section = ".init.rust"]
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn ulp_riscv_halt() {
|
||||
unsafe { &*pac::RTC_CNTL::PTR }.cocpu_ctrl().modify(|_, w| {
|
||||
w.cocpu_shut_2_clk_dis()
|
||||
.variant(0x3f)
|
||||
.cocpu_done()
|
||||
.set_bit()
|
||||
});
|
||||
|
||||
loop {
|
||||
riscv::asm::wfi();
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
//! Low-power UART driver
|
||||
|
||||
use esp32c6_lp::LP_UART;
|
||||
use crate::pac::LP_UART;
|
||||
|
||||
const UART_FIFO_SIZE: u16 = 128;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn conjour() -> Option<LpUart> {
|
||||
pub unsafe fn conjure() -> Option<LpUart> {
|
||||
Some(LpUart {
|
||||
uart: LP_UART::steal(),
|
||||
})
|
||||
@ -154,7 +154,8 @@ impl core::fmt::Write for LpUart {
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_hal::serial::Read<u8> for LpUart {
|
||||
#[cfg(feature = "embedded-hal-02")]
|
||||
impl embedded_hal_02::serial::Read<u8> for LpUart {
|
||||
type Error = Error;
|
||||
|
||||
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||
@ -162,7 +163,8 @@ impl embedded_hal::serial::Read<u8> for LpUart {
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_hal::serial::Write<u8> for LpUart {
|
||||
#[cfg(feature = "embedded-hal-02")]
|
||||
impl embedded_hal_02::serial::Write<u8> for LpUart {
|
||||
type Error = Error;
|
||||
|
||||
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
|
@ -1,11 +0,0 @@
|
||||
[target.riscv32imc-unknown-none-elf]
|
||||
runner = "espflash flash --monitor"
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
]
|
||||
|
||||
[build]
|
||||
target = "riscv32imc-unknown-none-elf"
|
||||
|
||||
[unstable]
|
||||
build-std = ["core"]
|
@ -1,22 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Add the `ulp-riscv-hal` package (#840)
|
||||
|
||||
### Changed
|
||||
|
||||
- Renamed to `esp-ulp-riscv-hal` (#916)
|
||||
|
||||
### Fixed
|
||||
|
||||
### Removed
|
||||
|
||||
[Unreleased]: https://github.com/esp-rs/esp-hal/commits/main/esp-ulp-riscv-hal
|
@ -1,38 +0,0 @@
|
||||
[package]
|
||||
name = "esp-ulp-riscv-hal"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.67.0"
|
||||
description = "HAL for ESP32-S2 / ESP32-S3 ULP RISC-V coprocessor"
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
keywords = [
|
||||
"embedded",
|
||||
"embedded-hal",
|
||||
"esp",
|
||||
"esp32s2",
|
||||
"esp32s3",
|
||||
"no-std",
|
||||
]
|
||||
categories = [
|
||||
"embedded",
|
||||
"hardware-support",
|
||||
"no-std",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
embedded-hal = { version = "0.2.7", features = ["unproven"] }
|
||||
procmacros = { package = "esp-hal-procmacros", path = "../esp-hal-procmacros" }
|
||||
paste = "1.0.14"
|
||||
esp32s2-ulp = { version = "0.1.0", optional = true }
|
||||
esp32s3-ulp = { version = "0.1.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
panic-halt = "0.2.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
debug = []
|
||||
esp32s2 = ["dep:esp32s2-ulp", "procmacros/esp32s2-ulp"]
|
||||
esp32s3 = ["dep:esp32s3-ulp", "procmacros/esp32s3-ulp"]
|
@ -1,53 +0,0 @@
|
||||
# ulp-lp-hal
|
||||
|
||||
[](https://crates.io/crates/esp-ulp-lp-hal)
|
||||
[](https://docs.rs/esp-ulp-lp-hal)
|
||||

|
||||
[](https://matrix.to/#/#esp-rs:matrix.org)
|
||||
|
||||
`no_std` HAL for the ESP32-S2/ESP32-S3 from Espressif's ultra-low-power coprocessor.
|
||||
|
||||
Implements a number of the traits defined in [embedded-hal](https://github.com/rust-embedded/embedded-hal).
|
||||
|
||||
This device uses the RISC-V ISA, which is officially supported by the Rust compiler via the `riscv32imc-unknown-none-elf` target.
|
||||
|
||||
Please refer to the documentation for more information.
|
||||
|
||||
## [Documentation]
|
||||
|
||||
[documentation]: https://docs.rs/esp-ulp-lp-hal/
|
||||
|
||||
## Resources
|
||||
|
||||
- [Datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf)
|
||||
- [Datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf)
|
||||
- [Technical Reference Manual](https://www.espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf)
|
||||
- [Technical Reference Manual](https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf)
|
||||
- [The Rust Programming Language](https://doc.rust-lang.org/book/)
|
||||
- [The Embedded Rust Book](https://docs.rust-embedded.org/book/index.html)
|
||||
- [The Rust on ESP Book](https://esp-rs.github.io/book/)
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Installing the Rust Compiler Target
|
||||
|
||||
The compilation target for this device is officially supported by the mainline Rust compiler and can be installed using [rustup](https://rustup.rs/):
|
||||
|
||||
```shell
|
||||
rustup target add riscv32imc-unknown-none-elf
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of:
|
||||
|
||||
- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in
|
||||
the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without
|
||||
any additional terms or conditions.
|
@ -1,17 +0,0 @@
|
||||
use std::{env, fs::File, io::Write, path::PathBuf};
|
||||
|
||||
fn main() {
|
||||
// Put the linker script somewhere the linker can find it
|
||||
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
|
||||
File::create(out.join("link.x"))
|
||||
.unwrap()
|
||||
.write_all(include_bytes!("ld/link.x"))
|
||||
.unwrap();
|
||||
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
|
||||
// Only re-run the build script when memory.x is changed,
|
||||
// instead of when any part of the source code changes.
|
||||
println!("cargo:rerun-if-changed=ld/memory.x");
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
//! Counts a 32 bit value at 0x5000_0400 (0x400 from the ULP's point of view)
|
||||
//! and blinks GPIO 1.
|
||||
//!
|
||||
//! Make sure the RTC RAM is cleared before loading the code.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use esp_ulp_riscv_hal::{
|
||||
delay::Delay,
|
||||
gpio::{GpioPin, Output, PushPull},
|
||||
prelude::*,
|
||||
};
|
||||
use panic_halt as _;
|
||||
|
||||
#[entry]
|
||||
fn main(mut gpio1: GpioPin<Output<PushPull>, 1>) -> ! {
|
||||
let mut i: u32 = 0;
|
||||
|
||||
let ptr = 0x400 as *mut u32;
|
||||
let mut delay = Delay::new();
|
||||
|
||||
loop {
|
||||
i = i.wrapping_add(1u32);
|
||||
unsafe {
|
||||
ptr.write_volatile(i);
|
||||
}
|
||||
|
||||
gpio1.set_high().unwrap();
|
||||
delay.delay_ms(500);
|
||||
|
||||
gpio1.set_low().unwrap();
|
||||
delay.delay_ms(500);
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
//! Simple blocking delay functionality
|
||||
//!
|
||||
//! This uses cycle count under the hood.
|
||||
|
||||
use core::arch::asm;
|
||||
|
||||
use embedded_hal::blocking::delay::{DelayMs, DelayUs};
|
||||
|
||||
// see components\ulp\ulp_riscv\ulp_core\include\ulp_riscv_utils.h in esp-idf
|
||||
#[cfg(feature = "esp32s2")]
|
||||
const CYCLES_PER_US_M10: u32 = 85;
|
||||
#[cfg(feature = "esp32s3")]
|
||||
const CYCLES_PER_US_M10: u32 = 175;
|
||||
|
||||
pub struct Delay {}
|
||||
|
||||
impl Delay {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Delay {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayUs<u64> for Delay {
|
||||
#[inline(always)]
|
||||
fn delay_us(&mut self, us: u64) {
|
||||
DelayUs::<u32>::delay_us(self, us as u32);
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayUs<u32> for Delay {
|
||||
#[inline(always)]
|
||||
fn delay_us(&mut self, us: u32) {
|
||||
let t0 = cycles();
|
||||
let clock = us * CYCLES_PER_US_M10 / 10;
|
||||
while cycles().wrapping_sub(t0) <= clock {}
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayMs<u32> for Delay {
|
||||
#[inline(always)]
|
||||
fn delay_ms(&mut self, ms: u32) {
|
||||
DelayUs::<u32>::delay_us(self, ms * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn cycles() -> u32 {
|
||||
let mut cycles;
|
||||
unsafe {
|
||||
asm!(
|
||||
"rdcycle {cycles}",
|
||||
cycles = out(reg) cycles,
|
||||
)
|
||||
}
|
||||
cycles
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
//! Low-power GPIO driver
|
||||
//!
|
||||
//! It's assumed that GPIOs are already configured correctly by the HP core.
|
||||
|
||||
use core::{convert::Infallible, marker::PhantomData};
|
||||
|
||||
use crate::pac::RTC_IO;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn conjour<MODE, const PIN: u8>() -> Option<GpioPin<MODE, PIN>> {
|
||||
if PIN > 7 {
|
||||
None
|
||||
} else {
|
||||
Some(GpioPin {
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Unknown {}
|
||||
|
||||
pub struct Input<MODE> {
|
||||
_mode: PhantomData<MODE>,
|
||||
}
|
||||
|
||||
pub struct Floating;
|
||||
|
||||
pub struct PullDown;
|
||||
|
||||
pub struct PullUp;
|
||||
|
||||
pub struct Output<MODE> {
|
||||
_mode: PhantomData<MODE>,
|
||||
}
|
||||
|
||||
pub struct PushPull;
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct GpioPin<MODE, const PIN: u8> {
|
||||
phantom: PhantomData<MODE>,
|
||||
}
|
||||
|
||||
impl<MODE, const PIN: u8> GpioPin<Input<MODE>, PIN> {
|
||||
fn input_state(&self) -> bool {
|
||||
unsafe { &*RTC_IO::PTR }.rtc_gpio_in().read().bits() >> PIN & 0x1 != 0
|
||||
}
|
||||
}
|
||||
|
||||
impl<MODE, const PIN: u8> GpioPin<Output<MODE>, PIN> {
|
||||
fn output_state(&self) -> bool {
|
||||
unsafe { &*RTC_IO::PTR }.rtc_gpio_out().read().bits() >> PIN & 0x1 != 0
|
||||
}
|
||||
|
||||
fn set_output_low(&mut self) {
|
||||
// TODO align PAC
|
||||
|
||||
#[cfg(feature = "esp32s2")]
|
||||
unsafe { &*RTC_IO::PTR }
|
||||
.rtc_gpio_out_w1tc()
|
||||
.write(|w| w.gpio_out_data_w1tc().variant(1 << PIN));
|
||||
|
||||
#[cfg(feature = "esp32s3")]
|
||||
unsafe { &*RTC_IO::PTR }
|
||||
.rtc_gpio_out_w1tc()
|
||||
.write(|w| w.rtc_gpio_out_data_w1tc().variant(1 << PIN));
|
||||
}
|
||||
|
||||
fn set_output_high(&mut self) {
|
||||
#[cfg(feature = "esp32s2")]
|
||||
unsafe { &*RTC_IO::PTR }
|
||||
.rtc_gpio_out_w1ts()
|
||||
.write(|w| w.gpio_out_data_w1ts().variant(1 << PIN));
|
||||
|
||||
#[cfg(feature = "esp32s3")]
|
||||
unsafe { &*RTC_IO::PTR }
|
||||
.rtc_gpio_out_w1ts()
|
||||
.write(|w| w.rtc_gpio_out_data_w1ts().variant(1 << PIN));
|
||||
}
|
||||
}
|
||||
|
||||
impl<MODE, const PIN: u8> embedded_hal::digital::v2::InputPin for GpioPin<Input<MODE>, PIN> {
|
||||
type Error = Infallible;
|
||||
|
||||
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.input_state())
|
||||
}
|
||||
|
||||
fn is_low(&self) -> Result<bool, Self::Error> {
|
||||
Ok(!self.is_high()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<MODE, const PIN: u8> embedded_hal::digital::v2::OutputPin for GpioPin<Output<MODE>, PIN> {
|
||||
type Error = Infallible;
|
||||
|
||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||
self.set_output_low();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||
self.set_output_high();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<MODE, const PIN: u8> embedded_hal::digital::v2::StatefulOutputPin
|
||||
for GpioPin<Output<MODE>, PIN>
|
||||
{
|
||||
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.output_state())
|
||||
}
|
||||
|
||||
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
||||
Ok(!self.is_set_high()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<MODE, const PIN: u8> embedded_hal::digital::v2::toggleable::Default
|
||||
for GpioPin<Output<MODE>, PIN>
|
||||
{
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
#![no_std]
|
||||
#![allow(asm_sub_register)]
|
||||
|
||||
use core::arch::global_asm;
|
||||
|
||||
pub mod delay;
|
||||
pub mod gpio;
|
||||
pub mod prelude;
|
||||
|
||||
#[cfg(feature = "esp32s2")]
|
||||
use esp32s2_ulp as pac;
|
||||
#[cfg(feature = "esp32s3")]
|
||||
use esp32s3_ulp as pac;
|
||||
|
||||
global_asm!(
|
||||
r#"
|
||||
.section .text.vectors
|
||||
.global irq_vector
|
||||
.global reset_vector
|
||||
|
||||
/* The reset vector, jumps to startup code */
|
||||
reset_vector:
|
||||
j __start
|
||||
|
||||
/* Interrupt handler */
|
||||
.balign 16
|
||||
irq_vector:
|
||||
ret
|
||||
|
||||
.section .text
|
||||
|
||||
__start:
|
||||
/* setup the stack pointer */
|
||||
la sp, __stack_top
|
||||
|
||||
call ulp_riscv_rescue_from_monitor
|
||||
call rust_main
|
||||
call ulp_riscv_halt
|
||||
loop:
|
||||
j loop
|
||||
"#
|
||||
);
|
||||
|
||||
#[link_section = ".init.rust"]
|
||||
#[export_name = "rust_main"]
|
||||
unsafe extern "C" fn lp_core_startup() -> ! {
|
||||
extern "Rust" {
|
||||
fn main() -> !;
|
||||
}
|
||||
|
||||
main();
|
||||
}
|
||||
|
||||
#[link_section = ".init.rust"]
|
||||
#[export_name = "ulp_riscv_rescue_from_monitor"]
|
||||
unsafe extern "C" fn ulp_riscv_rescue_from_monitor() {
|
||||
// Rescue RISCV from monitor state.
|
||||
let rtc_cntl = unsafe { pac::RTC_CNTL::steal() };
|
||||
|
||||
// TODO align naming in PACs
|
||||
#[cfg(feature = "esp32s2")]
|
||||
rtc_cntl
|
||||
.cocpu_ctrl()
|
||||
.modify(|_, w| w.cocpu_done().clear_bit().cocpu_shut_reset_en().clear_bit());
|
||||
#[cfg(feature = "esp32s3")]
|
||||
rtc_cntl
|
||||
.rtc_cocpu_ctrl()
|
||||
.modify(|_, w| w.cocpu_done().clear_bit().cocpu_shut_reset_en().clear_bit());
|
||||
}
|
||||
|
||||
#[link_section = ".init.rust"]
|
||||
#[export_name = "ulp_riscv_halt"]
|
||||
unsafe extern "C" fn ulp_riscv_halt() {
|
||||
let rtc_cntl = unsafe { pac::RTC_CNTL::steal() };
|
||||
|
||||
// TODO align naming in PACs
|
||||
#[cfg(feature = "esp32s2")]
|
||||
{
|
||||
rtc_cntl
|
||||
.cocpu_ctrl()
|
||||
.modify(|_, w| w.cocpu_shut_2_clk_dis().variant(0x3f));
|
||||
|
||||
rtc_cntl
|
||||
.cocpu_ctrl()
|
||||
.modify(|_, w| w.cocpu_done().set_bit());
|
||||
}
|
||||
#[cfg(feature = "esp32s3")]
|
||||
{
|
||||
rtc_cntl
|
||||
.rtc_cocpu_ctrl()
|
||||
.modify(|_, w| w.cocpu_shut_2_clk_dis().variant(0x3f));
|
||||
|
||||
rtc_cntl
|
||||
.rtc_cocpu_ctrl()
|
||||
.modify(|_, w| w.cocpu_done().set_bit());
|
||||
}
|
||||
|
||||
#[allow(clippy::empty_loop)]
|
||||
loop {}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
//! The prelude
|
||||
//!
|
||||
//! Re-exports all traits required for interacting with the various peripheral
|
||||
//! drivers implemented in this crate.
|
||||
|
||||
pub use embedded_hal::{
|
||||
digital::v2::{
|
||||
InputPin as _embedded_hal_digital_vs_InputPin,
|
||||
OutputPin as _embedded_hal_digital_vs_OutputPin,
|
||||
StatefulOutputPin as _embedded_hal_digital_vs_StatefulOutputPin,
|
||||
ToggleableOutputPin as _embedded_hal_digital_vs_ToggleableOutputPin,
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
pub use procmacros::entry;
|
@ -3,7 +3,7 @@
|
||||
//! Code on LP core increments a counter and continuously toggles GPIO1. The
|
||||
//! current value is printed by the HP core.
|
||||
//!
|
||||
//! Make sure to first compile the `esp32c6-lp-hal/examples/blinky.rs` example
|
||||
//! Make sure to first compile the `esp-lp-hal/examples/blinky.rs` example
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
@ -35,9 +35,8 @@ fn main() -> ! {
|
||||
println!("lp core stopped");
|
||||
|
||||
// load code to LP core
|
||||
let lp_core_code = load_lp_code!(
|
||||
"../esp32c6-lp-hal/target/riscv32imac-unknown-none-elf/release/examples/blinky"
|
||||
);
|
||||
let lp_core_code =
|
||||
load_lp_code!("../esp-lp-hal/target/riscv32imac-unknown-none-elf/release/examples/blinky");
|
||||
|
||||
// start LP core
|
||||
lp_core_code.run(&mut lp_core, lp_core::LpCoreWakeupSource::HpCpu, lp_pin);
|
||||
|
@ -1,8 +1,9 @@
|
||||
//! This shows a very basic example of running code on the LP core.
|
||||
//!
|
||||
//! Code on LP core uses LP_UART initialized on HP core. For more information
|
||||
//! check `lp_core_uart` example in the `esp32c6-lp-hal.
|
||||
//! Make sure to first compile the `esp32c6-lp-hal/examples/uart.rs` example
|
||||
//! check `lp_core_uart` example in the `esp-lp-hal.
|
||||
//!
|
||||
//! Make sure to first compile the `esp-lp-hal/examples/uart.rs` example
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
@ -60,9 +61,8 @@ fn main() -> ! {
|
||||
println!("lp core stopped");
|
||||
|
||||
// load code to LP core
|
||||
let lp_core_code = load_lp_code!(
|
||||
"../esp32c6-lp-hal/target/riscv32imac-unknown-none-elf/release/examples/uart"
|
||||
);
|
||||
let lp_core_code =
|
||||
load_lp_code!("../esp-lp-hal/target/riscv32imac-unknown-none-elf/release/examples/uart");
|
||||
|
||||
// start LP core
|
||||
lp_core_code.run(&mut lp_core, lp_core::LpCoreWakeupSource::HpCpu, lp_uart);
|
||||
|
@ -1,11 +0,0 @@
|
||||
[target.riscv32imac-unknown-none-elf]
|
||||
runner = "espflash flash --monitor"
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
]
|
||||
|
||||
[build]
|
||||
target = "riscv32imac-unknown-none-elf"
|
||||
|
||||
[unstable]
|
||||
build-std = ["core"]
|
@ -1,37 +0,0 @@
|
||||
[package]
|
||||
name = "esp32c6-lp-hal"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.67.0"
|
||||
description = "HAL for ESP32-C6's low-power coprocessor"
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
keywords = [
|
||||
"embedded",
|
||||
"embedded-hal",
|
||||
"esp",
|
||||
"esp32c6",
|
||||
"no-std",
|
||||
]
|
||||
categories = [
|
||||
"embedded",
|
||||
"hardware-support",
|
||||
"no-std",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
critical-section = { version = "1.1.2", features = ["restore-state-u8"] }
|
||||
embedded-hal = { version = "0.2.7", features = ["unproven"] }
|
||||
esp32c6-lp = { version = "0.1.0", features = ["critical-section"] }
|
||||
nb = "1.1.0"
|
||||
paste = "1.0.14"
|
||||
procmacros = { package = "esp-hal-procmacros", path = "../esp-hal-procmacros", features = ["esp32c6-lp"] }
|
||||
riscv = "0.10.1"
|
||||
|
||||
[dev-dependencies]
|
||||
panic-halt = "0.2.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
debug = ["esp32c6-lp/impl-register-debug"]
|
@ -1,51 +0,0 @@
|
||||
# esp32c6-lp-hal
|
||||
|
||||
[](https://crates.io/crates/esp32c6-lp-hal)
|
||||
[](https://docs.rs/esp32c6-lp-hal)
|
||||

|
||||
[](https://matrix.to/#/#esp-rs:matrix.org)
|
||||
|
||||
`no_std` HAL for the ESP32-C6 from Espressif's low-power coprocessor.
|
||||
|
||||
Implements a number of the traits defined in [embedded-hal](https://github.com/rust-embedded/embedded-hal).
|
||||
|
||||
This device uses the RISC-V ISA, which is officially supported by the Rust compiler via the `riscv32imac-unknown-none-elf` target.
|
||||
|
||||
Please refer to the documentation for more information.
|
||||
|
||||
## [Documentation]
|
||||
|
||||
[documentation]: https://docs.rs/esp32c6-lp-hal/
|
||||
|
||||
## Resources
|
||||
|
||||
- [Datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf)
|
||||
- [Technical Reference Manual](https://www.espressif.com/sites/default/files/documentation/esp32-c6_technical_reference_manual_en.pdf)
|
||||
- [The Rust Programming Language](https://doc.rust-lang.org/book/)
|
||||
- [The Embedded Rust Book](https://docs.rust-embedded.org/book/index.html)
|
||||
- [The Rust on ESP Book](https://esp-rs.github.io/book/)
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Installing the Rust Compiler Target
|
||||
|
||||
The compilation target for this device is officially supported by the mainline Rust compiler and can be installed using [rustup](https://rustup.rs/):
|
||||
|
||||
```shell
|
||||
rustup target add riscv32imac-unknown-none-elf
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of:
|
||||
|
||||
- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in
|
||||
the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without
|
||||
any additional terms or conditions.
|
@ -1,15 +0,0 @@
|
||||
use std::{env, error::Error, fs, path::PathBuf};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
// 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());
|
||||
|
||||
fs::copy("ld/link.x", out.join("link.x"))?;
|
||||
|
||||
// Only re-run the build script when memory.x is changed,
|
||||
// instead of when any part of the source code changes.
|
||||
println!("cargo:rerun-if-changed=ld/memory.x");
|
||||
|
||||
Ok(())
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
//! Counts a 32 bit value at 0x5000_2000 and blinks GPIO 1.
|
||||
//! Make sure the LP RAM is cleared before loading the code.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use esp32c6_lp_hal::{
|
||||
delay::Delay,
|
||||
gpio::{GpioPin, Output, PushPull},
|
||||
prelude::*,
|
||||
};
|
||||
use panic_halt as _;
|
||||
|
||||
#[entry]
|
||||
fn main(mut gpio1: GpioPin<Output<PushPull>, 1>) -> ! {
|
||||
let mut i: u32 = 0;
|
||||
|
||||
let ptr = 0x5000_2000 as *mut u32;
|
||||
let mut delay = Delay::new();
|
||||
|
||||
loop {
|
||||
i = i.wrapping_add(1u32);
|
||||
unsafe {
|
||||
ptr.write_volatile(i);
|
||||
}
|
||||
|
||||
gpio1.set_high().unwrap();
|
||||
delay.delay_ms(500);
|
||||
|
||||
gpio1.set_low().unwrap();
|
||||
delay.delay_ms(500);
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
//! Simple blocking delay functionality
|
||||
//!
|
||||
//! This uses the delay functionality provided by the `riscv` crate under the
|
||||
//! hood.
|
||||
|
||||
use embedded_hal::blocking::delay::{DelayMs, DelayUs};
|
||||
|
||||
use crate::CPU_CLOCK;
|
||||
|
||||
pub struct Delay {
|
||||
rv_delay: riscv::delay::McycleDelay,
|
||||
}
|
||||
|
||||
impl Delay {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
rv_delay: riscv::delay::McycleDelay::new(unsafe { CPU_CLOCK }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Delay {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayUs<u64> for Delay {
|
||||
#[inline(always)]
|
||||
fn delay_us(&mut self, us: u64) {
|
||||
self.rv_delay.delay_us(us);
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayUs<u32> for Delay {
|
||||
#[inline(always)]
|
||||
fn delay_us(&mut self, us: u32) {
|
||||
self.rv_delay.delay_us(us);
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayMs<u32> for Delay {
|
||||
#[inline(always)]
|
||||
fn delay_ms(&mut self, ms: u32) {
|
||||
self.rv_delay.delay_ms(ms);
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
//! Low-power GPIO driver
|
||||
//!
|
||||
//! It's assumed that GPIOs are already configured correctly by the HP core.
|
||||
|
||||
use core::{convert::Infallible, marker::PhantomData};
|
||||
|
||||
use esp32c6_lp::LP_IO;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn conjour<MODE, const PIN: u8>() -> Option<GpioPin<MODE, PIN>> {
|
||||
if PIN > 7 {
|
||||
None
|
||||
} else {
|
||||
Some(GpioPin {
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Unknown {}
|
||||
|
||||
pub struct Input<MODE> {
|
||||
_mode: PhantomData<MODE>,
|
||||
}
|
||||
|
||||
pub struct Floating;
|
||||
|
||||
pub struct PullDown;
|
||||
|
||||
pub struct PullUp;
|
||||
|
||||
pub struct Output<MODE> {
|
||||
_mode: PhantomData<MODE>,
|
||||
}
|
||||
|
||||
pub struct PushPull;
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct GpioPin<MODE, const PIN: u8> {
|
||||
phantom: PhantomData<MODE>,
|
||||
}
|
||||
|
||||
impl<MODE, const PIN: u8> GpioPin<Input<MODE>, PIN> {
|
||||
fn input_state(&self) -> bool {
|
||||
unsafe { &*LP_IO::PTR }.in_().read().bits() >> PIN & 0x1 != 0
|
||||
}
|
||||
}
|
||||
|
||||
impl<MODE, const PIN: u8> GpioPin<Output<MODE>, PIN> {
|
||||
fn output_state(&self) -> bool {
|
||||
unsafe { &*LP_IO::PTR }.out().read().bits() >> PIN & 0x1 != 0
|
||||
}
|
||||
|
||||
fn set_output_low(&mut self) {
|
||||
unsafe { &*LP_IO::PTR }
|
||||
.out_w1tc()
|
||||
.write(|w| w.out_data_w1tc().variant(1 << PIN));
|
||||
}
|
||||
|
||||
fn set_output_high(&mut self) {
|
||||
unsafe { &*LP_IO::PTR }
|
||||
.out_w1ts()
|
||||
.write(|w| w.out_data_w1ts().variant(1 << PIN));
|
||||
}
|
||||
}
|
||||
|
||||
impl<MODE, const PIN: u8> embedded_hal::digital::v2::InputPin for GpioPin<Input<MODE>, PIN> {
|
||||
type Error = Infallible;
|
||||
|
||||
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.input_state())
|
||||
}
|
||||
|
||||
fn is_low(&self) -> Result<bool, Self::Error> {
|
||||
Ok(!self.is_high()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<MODE, const PIN: u8> embedded_hal::digital::v2::OutputPin for GpioPin<Output<MODE>, PIN> {
|
||||
type Error = Infallible;
|
||||
|
||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||
self.set_output_low();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||
self.set_output_high();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<MODE, const PIN: u8> embedded_hal::digital::v2::StatefulOutputPin
|
||||
for GpioPin<Output<MODE>, PIN>
|
||||
{
|
||||
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.output_state())
|
||||
}
|
||||
|
||||
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
||||
Ok(!self.is_set_high()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<MODE, const PIN: u8> embedded_hal::digital::v2::toggleable::Default
|
||||
for GpioPin<Output<MODE>, PIN>
|
||||
{
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
#![no_std]
|
||||
#![allow(asm_sub_register)]
|
||||
|
||||
use core::arch::global_asm;
|
||||
|
||||
pub mod delay;
|
||||
pub mod gpio;
|
||||
pub mod prelude;
|
||||
pub mod uart;
|
||||
|
||||
pub mod riscv {
|
||||
//! Low level access to RISC-V processors.
|
||||
//!
|
||||
//! Re-exports <https://crates.io/crates/riscv>
|
||||
|
||||
pub use riscv::*;
|
||||
}
|
||||
|
||||
// LP_FAST_CLK is not very accurate, for now use a rough estimate
|
||||
const LP_FAST_CLK_HZ: u32 = 16_000_000;
|
||||
const XTAL_D2_CLK_HZ: u32 = 20_000_000;
|
||||
|
||||
pub static mut CPU_CLOCK: u32 = LP_FAST_CLK_HZ;
|
||||
|
||||
global_asm!(
|
||||
r#"
|
||||
.section .init.vector, "ax"
|
||||
/* This is the vector table. It is currently empty, but will be populated
|
||||
* with exception and interrupt handlers when this is supported
|
||||
*/
|
||||
|
||||
.align 0x4, 0xff
|
||||
.global _vector_table
|
||||
.type _vector_table, @function
|
||||
_vector_table:
|
||||
.option push
|
||||
.option norvc
|
||||
|
||||
.rept 32
|
||||
nop
|
||||
.endr
|
||||
|
||||
.option pop
|
||||
.size _vector_table, .-_vector_table
|
||||
|
||||
.section .init, "ax"
|
||||
.global reset_vector
|
||||
|
||||
/* The reset vector, jumps to startup code */
|
||||
reset_vector:
|
||||
j __start
|
||||
|
||||
__start:
|
||||
/* setup the stack pointer */
|
||||
la sp, __stack_top
|
||||
call lp_core_startup
|
||||
loop:
|
||||
j loop
|
||||
"#
|
||||
);
|
||||
|
||||
#[link_section = ".init.rust"]
|
||||
#[export_name = "lp_core_startup"]
|
||||
unsafe extern "C" fn lp_core_startup() -> ! {
|
||||
extern "Rust" {
|
||||
fn main() -> !;
|
||||
}
|
||||
|
||||
let clkrst = &*esp32c6_lp::LP_CLKRST::PTR;
|
||||
if clkrst.lp_clk_conf().read().fast_clk_sel().bit_is_set() {
|
||||
CPU_CLOCK = XTAL_D2_CLK_HZ;
|
||||
}
|
||||
|
||||
main();
|
||||
}
|
||||
|
||||
mod critical_section_impl {
|
||||
struct CriticalSection;
|
||||
|
||||
critical_section::set_impl!(CriticalSection);
|
||||
|
||||
unsafe impl critical_section::Impl for CriticalSection {
|
||||
unsafe fn acquire() -> critical_section::RawRestoreState {
|
||||
let mut mstatus = 0u32;
|
||||
core::arch::asm!("csrrci {0}, mstatus, 8", inout(reg) mstatus);
|
||||
let interrupts_active = (mstatus & 0b1000) != 0;
|
||||
interrupts_active as _
|
||||
}
|
||||
|
||||
unsafe fn release(token: critical_section::RawRestoreState) {
|
||||
if token != 0 {
|
||||
riscv::interrupt::enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
//! The prelude
|
||||
//!
|
||||
//! Re-exports all traits required for interacting with the various peripheral
|
||||
//! drivers implemented in this crate.
|
||||
|
||||
pub use embedded_hal::{
|
||||
digital::v2::{
|
||||
InputPin as _embedded_hal_digital_vs_InputPin,
|
||||
OutputPin as _embedded_hal_digital_vs_OutputPin,
|
||||
StatefulOutputPin as _embedded_hal_digital_vs_StatefulOutputPin,
|
||||
ToggleableOutputPin as _embedded_hal_digital_vs_ToggleableOutputPin,
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
pub use procmacros::entry;
|
@ -29,9 +29,8 @@ fn main() -> ! {
|
||||
let mut ulp_core = ulp_core::UlpCore::new(peripherals.ULP_RISCV_CORE);
|
||||
|
||||
// load code to LP core
|
||||
let lp_core_code = load_lp_code!(
|
||||
"../esp-ulp-riscv-hal/target/riscv32imc-unknown-none-elf/release/examples/blinky"
|
||||
);
|
||||
let lp_core_code =
|
||||
load_lp_code!("../esp-lp-hal/target/riscv32imc-unknown-none-elf/release/examples/blinky");
|
||||
|
||||
// start LP core
|
||||
lp_core_code.run(&mut ulp_core, ulp_core::UlpCoreWakeupSource::HpCpu, pin);
|
||||
|
@ -31,9 +31,8 @@ fn main() -> ! {
|
||||
println!("ulp core stopped");
|
||||
|
||||
// load code to LP core
|
||||
let lp_core_code = load_lp_code!(
|
||||
"../esp-ulp-riscv-hal/target/riscv32imc-unknown-none-elf/release/examples/blinky"
|
||||
);
|
||||
let lp_core_code =
|
||||
load_lp_code!("../esp-lp-hal/target/riscv32imc-unknown-none-elf/release/examples/blinky");
|
||||
|
||||
// start LP core
|
||||
lp_core_code.run(&mut ulp_core, ulp_core::UlpCoreWakeupSource::HpCpu, pin);
|
||||
|
Loading…
x
Reference in New Issue
Block a user