Add ULP RISC-V HAL (#840)

This commit is contained in:
Björn Quentin 2023-10-10 16:32:52 +02:00 committed by GitHub
parent 44e968f7a8
commit 47821e6b3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 952 additions and 163 deletions

View File

@ -348,6 +348,26 @@ jobs:
- name: rustdoc
run: cd esp32h2-hal/ && cargo doc --features=eh1
ulp-riscv-hal:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- 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 ulp-riscv-hal (esp32s3)
run: cd ulp-riscv-hal/ && cargo +nightly build --release --features=esp32s3 --examples
# Ensure documentation can be built
- name: rustdoc
run: cd ulp-riscv-hal/ && cargo doc --features=esp32s3
esp32s2-hal:
runs-on: ubuntu-latest
@ -358,48 +378,58 @@ jobs:
default: true
buildtargets: esp32s2
ldproxy: false
- uses: dtolnay/rust-toolchain@v1
with:
target: riscv32imc-unknown-none-elf
toolchain: nightly
components: rust-src
- uses: Swatinem/rust-cache@v2
# build the ulp-riscv-hal examples first to make sure the examples which expect
# the ELF files to be present will compile
- name: build ulp-riscv-hal prerequisites
run: cd ulp-riscv-hal/ && cargo +nightly build --release --features=esp32s2 --examples
# Perform a full build initially to verify that the examples not only
# build, but also link successfully.
- name: check esp32s2-hal (no features)
run: cd esp32s2-hal/ && cargo build --examples
run: cd esp32s2-hal/ && cargo +esp build --examples
# Subsequent steps can just check the examples instead, as we're already
# confident that they link.
- name: check esp32s2-hal (common features)
run: |
cd esp32s2-hal/
cargo build --examples --features=eh1,ufmt,log
cargo build --examples --features=eh1,ufmt,defmt
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/
cargo check --example=embassy_hello_world --features=embassy,embassy-time-timg0,embassy-executor-thread
cargo check --example=embassy_multiprio --features=embassy,embassy-time-timg0,embassy-executor-interrupt
cargo +esp check --example=embassy_hello_world --features=embassy,embassy-time-timg0,embassy-executor-thread
cargo +esp check --example=embassy_multiprio --features=embassy,embassy-time-timg0,embassy-executor-interrupt
- name: check esp32s2-hal (embassy, timg0, async)
run: |
cd esp32s2-hal/
cargo check --example=embassy_wait --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo check --example=embassy_spi --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo check --example=embassy_serial --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo check --example=embassy_i2c --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo check --example=embassy_i2s_read --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo check --example=embassy_i2s_sound --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo check --example=embassy_rmt_rx --features=embassy,embassy-time-timg0,async,embassy-executor-thread --release
cargo check --example=embassy_rmt_tx --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo +esp check --example=embassy_wait --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo +esp check --example=embassy_spi --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo +esp check --example=embassy_serial --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo +esp check --example=embassy_i2c --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo +esp check --example=embassy_i2s_read --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo +esp check --example=embassy_i2s_sound --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo +esp check --example=embassy_rmt_rx --features=embassy,embassy-time-timg0,async,embassy-executor-thread --release
cargo +esp check --example=embassy_rmt_tx --features=embassy,embassy-time-timg0,async,embassy-executor-thread
- name: check esp32s2-hal (embassy, log/defmt)
run: |
cd esp32s2-hal/
cargo check --examples --features=embassy,embassy-time-timg0,embassy-executor-interrupt,embassy-executor-thread,defmt
cargo check --examples --features=embassy,embassy-time-timg0,embassy-executor-interrupt,embassy-executor-thread,log
cargo +esp check --examples --features=embassy,embassy-time-timg0,embassy-executor-interrupt,embassy-executor-thread,defmt
cargo +esp check --examples --features=embassy,embassy-time-timg0,embassy-executor-interrupt,embassy-executor-thread,log
- name: check esp32s2-hal (psram)
run: cd esp32s2-hal/ && cargo check --example=psram --features=psram-2m --release # This example requires release!
run: cd esp32s2-hal/ && cargo +esp check --example=psram --features=psram-2m --release # This example requires release!
# Ensure documentation can be built
- name: rustdoc
run: cd esp32s2-hal/ && cargo doc --features=eh1
run: cd esp32s2-hal/ && cargo +esp doc --features=eh1
esp32s3-hal:
runs-on: ubuntu-latest
@ -411,65 +441,75 @@ jobs:
default: true
buildtargets: esp32s3
ldproxy: false
- uses: dtolnay/rust-toolchain@v1
with:
target: riscv32imc-unknown-none-elf
toolchain: nightly
components: rust-src
- uses: Swatinem/rust-cache@v2
# build the ulp-riscv-hal examples first to make sure the examples which expect
# the ELF files to be present will compile
- name: build ulp-riscv-hal prerequisites
run: cd ulp-riscv-hal/ && cargo +nightly build --release --features=esp32s3 --examples
# Perform a full build initially to verify that the examples not only
# build, but also link successfully.
# We also use this as an opportunity to verify that the examples link
# for each supported image format.
- name: build esp32s3-hal (no features)
run: cd esp32s3-hal/ && cargo build --examples
run: cd esp32s3-hal/ && cargo +esp build --examples
- name: build esp32s3-hal (direct-boot)
run: cd esp32s3-hal/ && cargo build --examples --features=direct-boot
run: cd esp32s3-hal/ && cargo +esp build --examples --features=direct-boot
# Subsequent steps can just check the examples instead, as we're already
# confident that they link.
- name: check esp32s3-hal (common features)
run: |
cd esp32s3-hal/
cargo build --examples --features=eh1,ufmt,log
cargo build --examples --features=eh1,ufmt,defmt
cargo +esp build --examples --features=eh1,ufmt,log
cargo +esp build --examples --features=eh1,ufmt,defmt
- name: check esp32s3-hal (embassy, timg0)
run: |
cd esp32s3-hal/
cargo check --example=embassy_hello_world --features=embassy,embassy-time-timg0,embassy-executor-thread
cargo check --example=embassy_multicore --features=embassy,embassy-time-timg0,embassy-executor-thread
cargo check --example=embassy_multicore_interrupt --features=embassy,embassy-time-timg0,embassy-executor-interrupt
cargo check --example=embassy_multiprio --features=embassy,embassy-time-timg0,embassy-executor-interrupt
cargo +esp check --example=embassy_hello_world --features=embassy,embassy-time-timg0,embassy-executor-thread
cargo +esp check --example=embassy_multicore --features=embassy,embassy-time-timg0,embassy-executor-thread
cargo +esp check --example=embassy_multicore_interrupt --features=embassy,embassy-time-timg0,embassy-executor-interrupt
cargo +esp check --example=embassy_multiprio --features=embassy,embassy-time-timg0,embassy-executor-interrupt
- name: check esp32s3-hal (embassy, systick)
run: |
cd esp32s3-hal/
cargo check --example=embassy_hello_world --features=embassy,embassy-time-systick,embassy-executor-thread
cargo check --example=embassy_multicore --features=embassy,embassy-time-systick,embassy-executor-thread
cargo check --example=embassy_multicore_interrupt --features=embassy,embassy-time-systick,embassy-executor-interrupt
cargo check --example=embassy_multiprio --features=embassy,embassy-time-systick,embassy-executor-interrupt
cargo +esp check --example=embassy_hello_world --features=embassy,embassy-time-systick,embassy-executor-thread
cargo +esp check --example=embassy_multicore --features=embassy,embassy-time-systick,embassy-executor-thread
cargo +esp check --example=embassy_multicore_interrupt --features=embassy,embassy-time-systick,embassy-executor-interrupt
cargo +esp check --example=embassy_multiprio --features=embassy,embassy-time-systick,embassy-executor-interrupt
- name: check esp32s3-hal (embassy, timg0, async)
run: |
cd esp32s3-hal/
cargo check --example=embassy_wait --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo check --example=embassy_spi --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo check --example=embassy_serial --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo check --example=embassy_i2c --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo check --example=embassy_i2s_read --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo check --example=embassy_i2s_sound --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo check --example=embassy_rmt_rx --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo check --example=embassy_rmt_tx --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo +esp check --example=embassy_wait --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo +esp check --example=embassy_spi --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo +esp check --example=embassy_serial --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo +esp check --example=embassy_i2c --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo +esp check --example=embassy_i2s_read --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo +esp check --example=embassy_i2s_sound --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo +esp check --example=embassy_rmt_rx --features=embassy,embassy-time-timg0,async,embassy-executor-thread
cargo +esp check --example=embassy_rmt_tx --features=embassy,embassy-time-timg0,async,embassy-executor-thread
- name: check esp32s3-hal (embassy, systick, async)
run: |
cd esp32s3-hal/
cargo check --example=embassy_wait --features=embassy,embassy-time-systick,async,embassy-executor-thread
cargo check --example=embassy_spi --features=embassy,embassy-time-systick,async,embassy-executor-thread
cargo check --example=embassy_serial --features=embassy,embassy-time-systick,async,embassy-executor-thread
cargo check --example=embassy_i2c --features=embassy,embassy-time-systick,async,embassy-executor-thread
cargo +esp check --example=embassy_wait --features=embassy,embassy-time-systick,async,embassy-executor-thread
cargo +esp check --example=embassy_spi --features=embassy,embassy-time-systick,async,embassy-executor-thread
cargo +esp check --example=embassy_serial --features=embassy,embassy-time-systick,async,embassy-executor-thread
cargo +esp check --example=embassy_i2c --features=embassy,embassy-time-systick,async,embassy-executor-thread
- name: check esp32s3-hal (octal psram and psram)
run: | # This examples require release!
cd esp32s3-hal/
cargo check --example=octal_psram --features=opsram-2m --release
cargo check --example=psram --features=psram-2m --release
cargo +esp check --example=octal_psram --features=opsram-2m --release
cargo +esp check --example=psram --features=psram-2m --release
- name: check esp32s3-hal (embassy, log/defmt)
run: |
cd esp32s3-hal/
cargo check --examples --features=embassy,embassy-time-timg0,embassy-executor-interrupt,embassy-executor-thread,defmt
cargo check --examples --features=embassy,embassy-time-timg0,embassy-executor-interrupt,embassy-executor-thread,log
cargo +esp check --examples --features=embassy,embassy-time-timg0,embassy-executor-interrupt,embassy-executor-thread,defmt
cargo +esp check --examples --features=embassy,embassy-time-timg0,embassy-executor-interrupt,embassy-executor-thread,log
# Ensure documentation can be built
- name: rustdoc
run: cd esp32s3-hal/ && cargo doc --features=eh1
@ -547,24 +587,34 @@ jobs:
with:
ldproxy: false
version: "1.67.0"
- uses: dtolnay/rust-toolchain@v1
with:
target: riscv32imc-unknown-none-elf
toolchain: "1.67"
components: rust-src
- uses: Swatinem/rust-cache@v2
# build the ulp-riscv-hal examples first to make sure the examples which expect
# the ELF files to be present will compile
- name: build ulp-riscv-hal prerequisites
run: cd ulp-riscv-hal/ && RUSTC_BOOTSTRAP=1 cargo +1.67 build --release --features=esp32s3 --examples
# Verify the MSRV for all Xtensa chips.
- name: msrv (esp32-hal)
run: |
cd esp32-hal/
cargo check --features=eh1,ufmt,log
cargo check --features=defmt
cargo +esp check --features=eh1,ufmt,log
cargo +esp check --features=defmt
- name: msrv (esp32s2-hal)
run: |
cd esp32s2-hal/
cargo check --features=eh1,ufmt,log
cargo check --features=defmt
cargo +esp check --features=eh1,ufmt,log
cargo +esp check --features=defmt
- name: msrv (esp32s3-hal)
run: |
cd esp32s3-hal/
cargo check --features=eh1,ufmt,log
cargo check --features=defmt
cargo +esp check --features=eh1,ufmt,log
cargo +esp check --features=defmt
# --------------------------------------------------------------------------
# Lint
@ -593,6 +643,8 @@ jobs:
run: cargo +stable clippy --manifest-path=esp32c6-lp-hal/Cargo.toml -- -D warnings -A asm-sub-register
- name: clippy (esp32h2-hal)
run: cargo +stable clippy --manifest-path=esp32h2-hal/Cargo.toml -- -D warnings
- name: clippy (ulp-riscv-hal)
run: cargo +stable clippy --manifest-path=ulp-riscv-hal/Cargo.toml --features=esp32s3 -- -D warnings -A asm-sub-register
clippy-xtensa:
runs-on: ubuntu-latest
@ -652,3 +704,5 @@ jobs:
run: cargo fmt --all --manifest-path=esp32s2-hal/Cargo.toml -- --check
- name: rustfmt (esp32s3-hal)
run: cargo fmt --all --manifest-path=esp32s3-hal/Cargo.toml -- --check
- name: rustfmt (ulp-riscv-hal)
run: cargo fmt --all --manifest-path=ulp-riscv-hal/Cargo.toml -- --check

View File

@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- SYSTIMER ETM functionality (#828)
- Adding async support for RSA peripheral(doesn't work properly for `esp32` chip - issue will be created)(#790)
- Added sleep support for ESP32-C3 with timer and GPIO wakeups (#795)
- Support for ULP-RISCV including Delay and GPIO (#840)
### Changed

View File

@ -1461,6 +1461,11 @@ macro_rules! rtc_pins {
use crate::peripherals::RTC_IO;
let rtcio = unsafe{ &*RTC_IO::ptr() };
#[cfg(esp32s3)]
unsafe { crate::peripherals::SENS::steal() }.sar_peri_clk_gate_conf.modify(|_,w| w.iomux_clk_en().set_bit());
#[cfg(esp32s2)]
unsafe { crate::peripherals::SENS::steal() }.sar_io_mux_conf.modify(|_,w| w.iomux_clk_gate_en().set_bit());
// disable input
paste::paste!{
rtcio.$pin_reg.modify(|_,w| unsafe {w
@ -1501,6 +1506,21 @@ macro_rules! rtc_pins {
}
}
}
#[cfg(not(esp32))]
paste::paste!{
impl<MODE> crate::gpio::rtc_io::IntoLowPowerPin<$pin_num> for GpioPin<MODE, $pin_num> {
fn into_low_power(mut self) -> crate::gpio::rtc_io::LowPowerPin<Unknown, $pin_num> {
use crate::gpio::RTCPin;
self.rtc_set_config(false, true, crate::gpio::RtcFunction::Rtc);
crate::gpio::rtc_io::LowPowerPin {
private: core::marker::PhantomData::default(),
}
}
}
}
)?
};
@ -1987,6 +2007,168 @@ pub mod etm {
}
}
#[cfg(all(rtc_io, not(esp32)))]
pub mod rtc_io {
//! RTC IO
//!
//! # Overview
//!
//! The hardware provides a couple of GPIO pins with low power (LP)
//! capabilities and analog functions. These pins can be controlled by
//! either IO MUX or RTC IO.
//!
//! If controlled by RTC IO, these pins will bypass IO MUX and GPIO
//! matrix for the use by ULP and peripherals in RTC system.
//!
//! When configured as RTC GPIOs, the pins can still be controlled by ULP or
//! the peripherals in RTC system during chip Deep-sleep, and wake up the
//! chip from Deep-sleep.
//!
//! # Example
//! ```no_run
//! let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
//! // configure GPIO 1 as ULP output pin
//! let lp_pin = io.pins.gpio1.into_low_power().into_push_pull_output();
//! ```
use core::marker::PhantomData;
use super::{Floating, Input, Output, PullDown, PullUp, PushPull, Unknown};
/// A GPIO pin configured for low power operation
pub struct LowPowerPin<MODE, const PIN: u8> {
pub(crate) private: PhantomData<MODE>,
}
/// Configures a pin for use as a low power pin
pub trait IntoLowPowerPin<const PIN: u8> {
fn into_low_power(self) -> LowPowerPin<Unknown, { PIN }>;
}
impl<MODE, const PIN: u8> LowPowerPin<MODE, PIN> {
#[doc(hidden)]
pub fn output_enable(&self, enable: bool) {
let rtc_io = unsafe { crate::peripherals::RTC_IO::steal() };
if enable {
// TODO align PAC
#[cfg(esp32s2)]
rtc_io
.rtc_gpio_enable_w1ts
.write(|w| w.reg_rtcio_reg_gpio_enable_w1ts().variant(1 << PIN));
#[cfg(esp32s3)]
rtc_io
.rtc_gpio_enable_w1ts
.write(|w| w.rtc_gpio_enable_w1ts().variant(1 << PIN));
} else {
rtc_io
.enable_w1tc
.write(|w| w.enable_w1tc().variant(1 << PIN));
}
}
fn input_enable(&self, enable: bool) {
get_pin_reg(PIN).modify(|_, w| w.fun_ie().bit(enable));
}
fn pullup_enable(&self, enable: bool) {
get_pin_reg(PIN).modify(|_, w| w.rue().bit(enable));
}
fn pulldown_enable(&self, enable: bool) {
get_pin_reg(PIN).modify(|_, w| w.rde().bit(enable));
}
#[doc(hidden)]
pub fn set_level(&mut self, level: bool) {
let rtc_io = unsafe { &*crate::peripherals::RTC_IO::PTR };
// TODO align PACs
#[cfg(esp32s2)]
if level {
rtc_io
.rtc_gpio_out_w1ts
.write(|w| w.gpio_out_data_w1ts().variant(1 << PIN));
} else {
rtc_io
.rtc_gpio_out_w1tc
.write(|w| w.gpio_out_data_w1tc().variant(1 << PIN));
}
#[cfg(esp32s3)]
if level {
rtc_io
.rtc_gpio_out_w1ts
.write(|w| w.rtc_gpio_out_data_w1ts().variant(1 << PIN));
} else {
rtc_io
.rtc_gpio_out_w1tc
.write(|w| w.rtc_gpio_out_data_w1tc().variant(1 << PIN));
}
}
#[doc(hidden)]
pub fn get_level(&self) -> bool {
let rtc_io = unsafe { &*crate::peripherals::RTC_IO::PTR };
(rtc_io.rtc_gpio_in.read().bits() & 1 << PIN) != 0
}
/// Configures the pin as an input with the internal pull-up resistor
/// enabled.
pub fn into_pull_up_input(self) -> LowPowerPin<Input<PullUp>, PIN> {
self.input_enable(true);
self.pullup_enable(true);
self.pulldown_enable(false);
LowPowerPin {
private: PhantomData::default(),
}
}
/// Configures the pin as an input with the internal pull-down resistor
/// enabled.
pub fn into_pull_down_input(self) -> LowPowerPin<Input<PullDown>, PIN> {
self.input_enable(true);
self.pullup_enable(false);
self.pulldown_enable(true);
LowPowerPin {
private: PhantomData::default(),
}
}
/// Configures the pin as a floating input pin.
pub fn into_floating_input(self) -> LowPowerPin<Input<Floating>, PIN> {
self.input_enable(true);
self.pullup_enable(false);
self.pulldown_enable(false);
LowPowerPin {
private: PhantomData::default(),
}
}
/// Configures the pin as an output pin.
pub fn into_push_pull_output(self) -> LowPowerPin<Output<PushPull>, PIN> {
self.output_enable(true);
LowPowerPin {
private: PhantomData::default(),
}
}
}
#[cfg(esp32s3)]
#[inline(always)]
fn get_pin_reg(pin: u8) -> &'static crate::peripherals::rtc_io::TOUCH_PAD0 {
let rtc_io = unsafe { &*crate::peripherals::RTC_IO::PTR };
unsafe { core::mem::transmute((rtc_io.touch_pad0.as_ptr()).add(pin as usize)) }
}
#[cfg(esp32s2)]
#[inline(always)]
fn get_pin_reg(pin: u8) -> &'static crate::peripherals::rtc_io::TOUCH_PAD {
let rtc_io = unsafe { &*crate::peripherals::RTC_IO::PTR };
unsafe { core::mem::transmute((rtc_io.touch_pad[0].as_ptr()).add(pin as usize)) }
}
}
#[cfg(lp_io)]
pub mod lp_gpio {
//! Low Power IO (LP_IO)

View File

@ -35,8 +35,8 @@ esp32c2 = []
esp32c3 = []
esp32c6 = ["dep:object"]
esp32h2 = []
esp32s2 = []
esp32s3 = []
esp32s2 = ["dep:object"]
esp32s3 = ["dep:object"]
interrupt = []
rtc_slow = []

View File

@ -514,7 +514,7 @@ pub fn make_gpio_enum_dispatch_macro(input: TokenStream) -> TokenStream {
.into()
}
#[cfg(feature = "esp32c6")]
#[cfg(any(feature = "esp32c6", feature = "esp32s2", feature = "esp32s3"))]
#[proc_macro]
pub fn load_lp_code(input: TokenStream) -> TokenStream {
use object::{Object, ObjectSection, ObjectSymbol};
@ -524,9 +524,17 @@ pub fn load_lp_code(input: TokenStream) -> TokenStream {
#[cfg(feature = "esp32c6")]
let hal_crate = crate_name("esp32c6-hal");
#[cfg(feature = "esp32s2")]
let hal_crate = crate_name("esp32s2-hal");
#[cfg(feature = "esp32s3")]
let hal_crate = crate_name("esp32s3-hal");
#[cfg(feature = "esp32c6")]
let hal_crate_name = Ident::new("esp32c6_hal", Span::call_site().into());
#[cfg(feature = "esp32s2")]
let hal_crate_name = Ident::new("esp32s2_hal", Span::call_site().into());
#[cfg(feature = "esp32s3")]
let hal_crate_name = Ident::new("esp32s3_hal", Span::call_site().into());
let hal_crate = match hal_crate {
Ok(FoundCrate::Itself) => {
@ -577,12 +585,21 @@ pub fn load_lp_code(input: TokenStream) -> TokenStream {
let mut sections: Vec<object::Section> = sections
.into_iter()
.filter(|section| section.address() != 0)
.filter(|section| match section.kind() {
object::SectionKind::Text
| object::SectionKind::ReadOnlyData
| object::SectionKind::Data
| object::SectionKind::UninitializedData => true,
_ => false,
})
.collect();
sections.sort_by(|a, b| a.address().partial_cmp(&b.address()).unwrap());
let mut binary: Vec<u8> = Vec::new();
#[cfg(feature = "esp32c6")]
let mut last_address = 0x50_000_000;
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
let mut last_address = 0x0;
for section in sections {
if section.address() > last_address {
@ -602,7 +619,7 @@ pub fn load_lp_code(input: TokenStream) -> TokenStream {
if let None = magic_symbol {
return parse::Error::new(
Span::call_site().into(),
"Given file doesn't seem to be an LP core application.",
"Given file doesn't seem to be an LP/ULP core application.",
)
.to_compile_error()
.into();
@ -621,12 +638,28 @@ pub fn load_lp_code(input: TokenStream) -> TokenStream {
.filter(|v: &proc_macro2::TokenStream| !v.is_empty())
.collect();
#[cfg(feature = "esp32c6")]
let imports = quote! {
use #hal_crate::lp_core::LpCore;
use #hal_crate::lp_core::LpCoreWakeupSource;
use #hal_crate::gpio::lp_gpio::LowPowerPin;
use #hal_crate::gpio::*;
};
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
let imports = quote! {
use #hal_crate::ulp_core::UlpCore as LpCore;
use #hal_crate::ulp_core::UlpCoreWakeupSource as LpCoreWakeupSource;
use #hal_crate::gpio::*;
};
#[cfg(feature = "esp32c6")]
let rtc_code_start = quote! { _rtc_fast_data_start };
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
let rtc_code_start = quote! { _rtc_slow_data_start };
quote! {
{
use #hal_crate::lp_core::LpCore;
use #hal_crate::lp_core::LpCoreWakeupSource;
use #hal_crate::gpio::lp_gpio::LowPowerPin;
use #hal_crate::gpio::*;
#imports
struct LpCoreCode {
}
@ -634,11 +667,11 @@ pub fn load_lp_code(input: TokenStream) -> TokenStream {
static LP_CODE: &[u8] = &[#(#binary),*];
extern "C" {
static _rtc_fast_data_start: u32;
static #rtc_code_start: u32;
}
unsafe {
core::ptr::copy_nonoverlapping(LP_CODE as *const _ as *const u8, &_rtc_fast_data_start as *const u32 as *mut u8, LP_CODE.len());
core::ptr::copy_nonoverlapping(LP_CODE as *const _ as *const u8, &#rtc_code_start as *const u32 as *mut u8, LP_CODE.len());
}
impl LpCoreCode {

View File

@ -1,33 +0,0 @@
[package]
name = "esp32c6-lp-hal-procmacros"
version = "0.1.0"
edition = "2021"
rust-version = "1.67.0"
description = "Procedural macros for the ESP32-C6's LP 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",
]
[lib]
proc-macro = true
[dependencies]
litrs = "0.4.0"
proc-macro-crate = "1.3.1"
proc-macro-error = "1.0.4"
proc-macro2 = "1.0.63"
quote = "1.0.28"
syn = {version = "2.0.22", features = ["extra-traits", "full"]}
toml_edit = "0.20.0"

View File

@ -24,7 +24,7 @@ categories = [
critical-section = { version = "1.1.2", features = ["restore-state-u8"] }
embedded-hal = { version = "0.2.7", features = ["unproven"] }
esp32c6-lp = { git = "https://github.com/esp-rs/esp-pacs", rev = "a9cad5e", features = ["critical-section"] }
esp32c6-lp-hal-procmacros = { path = "../esp32c6-lp-hal-procmacros" }
lp-hal-procmacros = { path = "../lp-hal-procmacros", features = ["esp32c6"] }
riscv = "0.10.1"
paste = "1.0.14"

View File

@ -12,4 +12,4 @@ pub use embedded_hal::{
},
prelude::*,
};
pub use esp32c6_lp_hal_procmacros::entry;
pub use lp_hal_procmacros::entry;

View File

@ -1,32 +1,21 @@
//! This shows a very basic example of running code on the ULP RISCV core.
//!
//! Code on ULP core just increments a counter. The current value is printed by
//! the HP core.
//! Code on ULP core just increments a counter and blinks GPIO 1. The current
//! value is printed by the HP core.
#![no_std]
#![no_main]
use esp32s2_hal::{clock::ClockControl, peripherals::Peripherals, prelude::*};
use esp32s2_hal::{
clock::ClockControl,
gpio::rtc_io::*,
peripherals::Peripherals,
prelude::*,
ulp_core,
IO,
};
use esp_backtrace as _;
use esp_println::println;
// 50000000 <_start>:
// 50000000: 00000517 auipc a0,0x0
// 50000004: 01050513 addi a0,a0,16 # 50000010 <data>
// 50000008: 4581 li a1,0
//
// 5000000a <_loop>:
// 5000000a: 0585 addi a1,a1,1
// 5000000c: c10c sw a1,0(a0)
// 5000000e: bff5 j 5000000a <_loop>
//
// 50000010 <data>:
// 50000010: 0000 0000
const CODE: &[u8] = &[
0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x05, 0x01, 0x81, 0x45, 0x85, 0x05, 0x0c, 0xc1, 0xf5, 0xbf,
0x00, 0x00, 0x00, 0x00,
];
use esp_println::{print, println};
#[entry]
fn main() -> ! {
@ -34,21 +23,24 @@ fn main() -> ! {
let system = peripherals.SYSTEM.split();
let _clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let mut ulp_core = esp32s2_hal::ulp_core::UlpCore::new(peripherals.ULP_RISCV_CORE);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let pin = io.pins.gpio1.into_low_power().into_push_pull_output();
// copy code to RTC ram
let lp_ram = 0x5000_0000 as *mut u8;
unsafe {
core::ptr::copy_nonoverlapping(CODE as *const _ as *const u8, lp_ram, CODE.len());
}
println!("copied code (len {})", CODE.len());
let mut ulp_core = ulp_core::UlpCore::new(peripherals.ULP_RISCV_CORE);
// start ULP core
ulp_core.run(esp32s2_hal::ulp_core::UlpCoreWakeupSource::HpCpu);
// load code to LP core
let lp_core_code = load_lp_code!(
"../ulp-riscv-hal/target/riscv32imc-unknown-none-elf/release/examples/blinky"
);
// start LP core
lp_core_code.run(&mut ulp_core, ulp_core::UlpCoreWakeupSource::HpCpu, pin);
println!("ulpcore run");
let data = (0x5000_0010 - 0) as *mut u32;
let data = (0x5000_0400) as *mut u32;
loop {
println!("Current {}", unsafe { data.read_volatile() });
print!("Current {:x} \u{000d}", unsafe {
data.read_volatile()
});
}
}

View File

@ -1,32 +1,21 @@
//! This shows a very basic example of running code on the ULP RISCV core.
//!
//! Code on ULP core just increments a counter. The current value is printed by
//! the HP core.
//! Code on ULP core just increments a counter and blinks GPIO 1. The current
//! value is printed by the HP core.
#![no_std]
#![no_main]
use esp32s3_hal::{clock::ClockControl, peripherals::Peripherals, prelude::*};
use esp32s3_hal::{
clock::ClockControl,
gpio::rtc_io::*,
peripherals::Peripherals,
prelude::*,
ulp_core,
IO,
};
use esp_backtrace as _;
use esp_println::println;
// 50000000 <_start>:
// 50000000: 00000517 auipc a0,0x0
// 50000004: 01050513 addi a0,a0,16 # 50000010 <data>
// 50000008: 4581 li a1,0
//
// 5000000a <_loop>:
// 5000000a: 0585 addi a1,a1,1
// 5000000c: c10c sw a1,0(a0)
// 5000000e: bff5 j 5000000a <_loop>
//
// 50000010 <data>:
// 50000010: 0000 0000
const CODE: &[u8] = &[
0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x05, 0x01, 0x81, 0x45, 0x85, 0x05, 0x0c, 0xc1, 0xf5, 0xbf,
0x00, 0x00, 0x00, 0x00,
];
use esp_println::{print, println};
#[entry]
fn main() -> ! {
@ -34,23 +23,26 @@ fn main() -> ! {
let system = peripherals.SYSTEM.split();
let _clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let mut ulp_core = esp32s3_hal::ulp_core::UlpCore::new(peripherals.ULP_RISCV_CORE);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let pin = io.pins.gpio1.into_low_power().into_push_pull_output();
let mut ulp_core = ulp_core::UlpCore::new(peripherals.ULP_RISCV_CORE);
ulp_core.stop();
println!("ulp core stopped");
// copy code to RTC ram
let lp_ram = 0x5000_0000 as *mut u8;
unsafe {
core::ptr::copy_nonoverlapping(CODE as *const _ as *const u8, lp_ram, CODE.len());
}
println!("copied code (len {})", CODE.len());
// load code to LP core
let lp_core_code = load_lp_code!(
"../ulp-riscv-hal/target/riscv32imc-unknown-none-elf/release/examples/blinky"
);
// start ULP core
ulp_core.run(esp32s3_hal::ulp_core::UlpCoreWakeupSource::HpCpu);
// start LP core
lp_core_code.run(&mut ulp_core, ulp_core::UlpCoreWakeupSource::HpCpu, pin);
println!("ulpcore run");
let data = (0x5000_0010 - 0) as *mut u32;
let data = (0x5000_0400) as *mut u32;
loop {
println!("Current {}", unsafe { data.read_volatile() });
print!("Current {:x} \u{000d}", unsafe {
data.read_volatile()
});
}
}

View File

@ -0,0 +1,36 @@
[package]
name = "lp-hal-procmacros"
version = "0.1.0"
edition = "2021"
rust-version = "1.67.0"
description = "Procedural macros for the LP/ULP coprocessors"
repository = "https://github.com/esp-rs/esp-hal"
license = "MIT OR Apache-2.0"
keywords = [
"embedded",
"embedded-hal",
"esp",
"esp32c6",
"esp32s2",
"esp32s3",
"no-std",
]
categories = ["embedded", "hardware-support", "no-std"]
[lib]
proc-macro = true
[dependencies]
litrs = "0.4.0"
proc-macro-crate = "1.3.1"
proc-macro-error = "1.0.4"
proc-macro2 = "1.0.63"
quote = "1.0.28"
syn = { version = "2.0.22", features = ["extra-traits", "full"] }
toml_edit = "0.20.0"
[features]
esp32c6 = []
esp32s2 = []
esp32s3 = []

View File

@ -8,11 +8,17 @@ use syn::{parse, parse_macro_input, spanned::Spanned, FnArg, ItemFn, PatType};
#[proc_macro_error]
#[proc_macro_attribute]
pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
#[cfg(feature = "esp32c6")]
let found_crate =
crate_name("esp32c6-lp-hal").expect("esp32c6_lp_hal is present in `Cargo.toml`");
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
let found_crate = crate_name("ulp-riscv-hal").expect("ulp-riscv-ha is present in `Cargo.toml`");
let hal_crate = match found_crate {
#[cfg(feature = "esp32c6")]
FoundCrate::Itself => quote!(esp32c6_lp_hal),
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
FoundCrate::Itself => quote!(ulp_riscv_hal),
FoundCrate::Name(name) => {
let ident = Ident::new(&name, Span::call_site());
quote!( #ident::Something )

View File

@ -0,0 +1,11 @@
[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"]

View File

@ -0,0 +1,22 @@
# 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 `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]
### Changed
### Fixed
### Removed
[Unreleased]: https://github.com/esp-rs/esp-hal/commits/main/esp32c6-lp-hal

39
ulp-riscv-hal/Cargo.toml Normal file
View File

@ -0,0 +1,39 @@
[package]
name = "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"] }
lp-hal-procmacros = { path = "../lp-hal-procmacros" }
paste = "1.0.14"
esp32s2-ulp = { git = "https://github.com/esp-rs/esp-pacs", package = "esp32s2-ulp", optional = true }
esp32s3-ulp = { git = "https://github.com/esp-rs/esp-pacs", package = "esp32s3-ulp", optional = true }
[dev-dependencies]
panic-halt = "0.2.0"
[features]
default = []
debug = []
esp32s2 = [ "dep:esp32s2-ulp", "lp-hal-procmacros/esp32s2" ]
esp32s3 = [ "dep:esp32s3-ulp", "lp-hal-procmacros/esp32s3" ]

53
ulp-riscv-hal/README.md Normal file
View File

@ -0,0 +1,53 @@
# ulp-lp-hal
[![Crates.io](https://img.shields.io/crates/v/ulp-lp-hal?labelColor=1C2C2E&color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/ulp-lp-hal)
[![docs.rs](https://img.shields.io/docsrs/ulp-lp-hal?labelColor=1C2C2E&color=C96329&logo=rust&style=flat-square)](https://docs.rs/ulp-lp-hal)
![Crates.io](https://img.shields.io/crates/l/ulp-lp-hal?labelColor=1C2C2E&style=flat-square)
[![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?label=join%20matrix&labelColor=1C2C2E&color=BEC5C9&logo=matrix&style=flat-square)](https://matrix.to/#/#esp-rs:matrix.org)
`no_std` HAL for the 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/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.

17
ulp-riscv-hal/build.rs Normal file
View File

@ -0,0 +1,17 @@
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");
}

View File

@ -0,0 +1,35 @@
//! 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 panic_halt as _;
use ulp_riscv_hal::{
delay::Delay,
gpio::{GpioPin, Output, PushPull},
prelude::*,
};
#[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);
}
}

53
ulp-riscv-hal/ld/link.x Normal file
View File

@ -0,0 +1,53 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
ENTRY(reset_vector)
CONFIG_ULP_COPROC_RESERVE_MEM = 8 * 1024;
MEMORY
{
ram(RW) : ORIGIN = 0, LENGTH = CONFIG_ULP_COPROC_RESERVE_MEM
}
SECTIONS
{
. = ORIGIN(ram);
.text :
{
*(.text.vectors) /* Default reset vector must link to offset 0x0 */
KEEP(*(.init));
KEEP(*(.init.rust));
*(.text)
*(.text*)
} >ram
.rodata ALIGN(4):
{
*(.rodata)
*(.rodata*)
} > ram
.data ALIGN(4):
{
*(.data)
*(.data*)
*(.sdata)
*(.sdata*)
} > ram
.bss ALIGN(4) :
{
*(.bss)
*(.bss*)
*(.sbss)
*(.sbss*)
} >ram
__stack_top = ORIGIN(ram) + LENGTH(ram);
}

View File

@ -0,0 +1,62 @@
//! 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
}

122
ulp-riscv-hal/src/gpio.rs Normal file
View File

@ -0,0 +1,122 @@
//! 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>
{
}

97
ulp-riscv-hal/src/lib.rs Normal file
View File

@ -0,0 +1,97 @@
#![no_std]
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 {}
}

View File

@ -0,0 +1,15 @@
//! 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 lp_hal_procmacros::entry;