Merge pull request #513 from esp-rs/feature/esp32h2

Add initial support for the ESP32-H2
This commit is contained in:
Jesse Braham 2023-05-09 10:06:32 -07:00 committed by GitHub
commit c5d8cc62b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 2704 additions and 97 deletions

View File

@ -44,6 +44,8 @@ jobs:
run: cd esp-hal-smartled/ && cargo +nightly-2023-03-09 check --features=esp32c3
- name: check (esp32c6)
run: cd esp-hal-smartled/ && cargo +nightly-2023-03-09 check --features=esp32c6
# - name: check (esp32h2)
# run: cd esp-hal-smartled/ && cargo +nightly-2023-03-09 check --features=esp32h2
# Check all Xtensa targets:
- name: check (esp32)
run: cd esp-hal-smartled/ && cargo +esp check --features=esp32,esp32_40mhz
@ -188,6 +190,39 @@ jobs:
- name: check esp32c6-hal (async, serial)
run: cd esp32c6-hal/ && cargo +nightly-2023-03-09 check --example=embassy_serial --features=embassy,embassy-time-systick,async
esp32h2-hal:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@v1
with:
target: riscv32imac-unknown-none-elf
toolchain: nightly-2023-03-09
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.
# We also use this as an opportunity to verify that the examples link
# for each supported image format.
- name: build esp32h2-hal (no features)
run: cd esp32h2-hal/ && cargo +nightly-2023-03-09 build --examples
# - name: build esp32h2-hal (direct-boot)
# run: cd esp32h2-hal/ && cargo +nightly-2023-03-09 build --examples --features=direct-boot
# Subsequent steps can just check the examples instead, as we're already
# confident that they link.
- name: check esp32h2-hal (common features)
run: cd esp32h2-hal/ && cargo +nightly-2023-03-09 check --examples --features=eh1,ufmt
# - name: check esp32h2-hal (async, systick)
# run: cd esp32h2-hal/ && cargo +nightly-2023-03-09 check --example=embassy_hello_world --features=embassy,embassy-time-systick
# - name: check esp32h2-hal (async, timg0)
# run: cd esp32h2-hal/ && cargo +nightly-2023-03-09 check --example=embassy_hello_world --features=embassy,embassy-time-timg0
# - name: check esp32h2-hal (async, gpio)
# run: cd esp32h2-hal/ && cargo +nightly-2023-03-09 check --example=embassy_wait --features=embassy,embassy-time-systick,async
# - name: check esp32h2-hal (async, spi)
# run: cd esp32h2-hal/ && cargo +nightly-2023-03-09 check --example=embassy_spi --features=embassy,embassy-time-systick,async
esp32s2-hal:
runs-on: ubuntu-latest
@ -276,6 +311,8 @@ jobs:
run: cd esp32c3-hal/ && cargo check --features=eh1,ufmt
- name: msrv (esp32c6-hal)
run: cd esp32c6-hal/ && cargo check --features=eh1,ufmt
- name: msrv (esp32h2-hal)
run: cd esp32h2-hal/ && cargo check --features=eh1,ufmt
msrv-xtensa:
runs-on: ubuntu-latest
@ -317,6 +354,8 @@ jobs:
run: cargo +stable clippy --manifest-path=esp32c3-hal/Cargo.toml -- --no-deps
- name: clippy (esp32c6-hal)
run: cargo +stable clippy --manifest-path=esp32c6-hal/Cargo.toml -- --no-deps
- name: clippy (esp32h2-hal)
run: cargo +stable clippy --manifest-path=esp32h2-hal/Cargo.toml -- --no-deps
clippy-xtensa:
runs-on: ubuntu-latest
@ -369,6 +408,8 @@ 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 (esp32h2-hal)
run: cargo fmt --all --manifest-path=esp32h2-hal/Cargo.toml -- --check
- name: rustfmt (esp32s2-hal)
run: cargo fmt --all --manifest-path=esp32s2-hal/Cargo.toml -- --check
- name: rustfmt (esp32s3-hal)

View File

@ -12,12 +12,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Add bare-bones PSRAM support for ESP32 (#506)
- Add initial support for the ESP32-H2 (#513)
### Fixed
- DMA is supported for SPI3 on ESP32-S3 (#507)
## [0.9.0] - 2023-05-02
### Added

View File

@ -4,7 +4,7 @@
![MIT/Apache-2.0 licensed](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue?style=flat-square)
[![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?label=join%20matrix&color=BEC5C9&logo=matrix&style=flat-square)](https://matrix.to/#/#esp-rs:matrix.org)
**H**ardware **A**bstraction **L**ayer crates for the **ESP32**, **ESP32-C2/C3/C6**, and **ESP32-S2/S3** from Espressif.
**H**ardware **A**bstraction **L**ayer crates for the **ESP32**, **ESP32-C2/C3/C6**, **ESP32-H2**, and **ESP32-S2/S3** from Espressif.
These HALs are `no_std`; if you are looking for `std` support, please use [esp-idf-hal] instead.
@ -18,6 +18,7 @@ If you have any questions, comments, or concerns, please [open an issue], [start
| [esp32c2-hal] | `riscv32imc-unknown-none-elf` | [ESP32-C2] |
| [esp32c3-hal] | `riscv32imc-unknown-none-elf` | [ESP32-C3] |
| [esp32c6-hal] | `riscv32imac-unknown-none-elf` | [ESP32-C6] |
| [esp32h2-hal] | `riscv32imac-unknown-none-elf` | _Currently unavailable_ |
| [esp32s2-hal] | `xtensa-esp32s2-none-elf` | [ESP32-S2] |
| [esp32s3-hal] | `xtensa-esp32s3-none-elf` | [ESP32-S3] |
@ -79,7 +80,7 @@ There are a number of other crates within the [esp-rs organization] which can be
The **M**inimum **S**upported **R**ust **V**ersions are:
- `1.65.0` for RISC-V devices (**ESP32-C2**, **ESP32-C3**, **ESP32-C6**)
- `1.65.0` for RISC-V devices (**ESP32-C2**, **ESP32-C3**, **ESP32-C6**, **ESP32-H2**)
- `1.65.0` for Xtensa devices (**ESP32**, **ESP32-S2**, **ESP32-S3**)
- `1.67.0` for all `async` examples (`embassy_hello_world`, `embassy_wait`, etc.)

View File

@ -55,6 +55,7 @@ esp32 = { version = "0.23.0", features = ["critical-section"], optional = true
esp32c2 = { version = "0.11.0", features = ["critical-section"], optional = true }
esp32c3 = { version = "0.14.0", features = ["critical-section"], optional = true }
esp32c6 = { version = "0.4.0", features = ["critical-section"], optional = true }
esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "5828519", package = "esp32h2", features = ["critical-section"], optional = true }
esp32s2 = { version = "0.14.0", features = ["critical-section"], optional = true }
esp32s3 = { version = "0.18.0", features = ["critical-section"], optional = true }
@ -67,6 +68,7 @@ esp32 = ["esp32/rt" , "xtensa", "xtensa-lx/esp32", "xtensa-lx-rt/esp32",
esp32c2 = ["esp32c2/rt", "riscv", "procmacros/esp32c2"]
esp32c3 = ["esp32c3/rt", "riscv", "procmacros/esp32c3"]
esp32c6 = ["esp32c6/rt", "riscv", "procmacros/esp32c6"]
esp32h2 = ["esp32h2/rt", "riscv", "procmacros/esp32h2"]
esp32s2 = ["esp32s2/rt", "xtensa", "xtensa-lx/esp32s2", "xtensa-lx-rt/esp32s2", "esp-synopsys-usb-otg", "usb-device", "procmacros/esp32s2"]
esp32s3 = ["esp32s3/rt", "xtensa", "xtensa-lx/esp32s3", "xtensa-lx-rt/esp32s3", "lock_api", "esp-synopsys-usb-otg", "usb-device", "procmacros/esp32s3"]

View File

@ -13,6 +13,7 @@ This crate should not be used directly; you should use one of the device-specifi
- [esp32c2-hal](../esp32c2-hal/README.md)
- [esp32c3-hal](../esp32c3-hal/README.md)
- [esp32c6-hal](../esp32c6-hal/README.md)
- [esp32h2-hal](../esp32h2-hal/README.md)
- [esp32s2-hal](../esp32s2-hal/README.md)
- [esp32s3-hal](../esp32s3-hal/README.md)

View File

@ -88,7 +88,9 @@ struct Config {
fn main() {
// NOTE: update when adding new device support!
// Ensure that exactly one chip has been specified:
assert_unique_used_features!("esp32", "esp32c2", "esp32c3", "esp32c6", "esp32s2", "esp32s3");
assert_unique_used_features!(
"esp32", "esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32s2", "esp32s3"
);
// Handle the features for the ESP32's different crystal frequencies:
#[cfg(feature = "esp32")]
@ -112,6 +114,8 @@ fn main() {
"esp32c3"
} else if cfg!(feature = "esp32c6") {
"esp32c6"
} else if cfg!(feature = "esp32h2") {
"esp32h2"
} else if cfg!(feature = "esp32s2") {
"esp32s2"
} else if cfg!(feature = "esp32s3") {

View File

@ -0,0 +1,64 @@
[device]
arch = "riscv"
cores = "single_core"
peripherals = [
# Peripherals available in the PAC:
# "aes",
"apb_saradc",
# "assist_debug",
# "ds",
# "ecc",
"efuse",
# "gdma",
"gpio",
# "hmac",
# "hp_apm",
# "hp_sys",
# "i2c0",
# "i2c1",
# "i2s0",
"interrupt_core0",
"intpri",
"io_mux",
# "ledc",
# "lp_ana",
# "lp_aon",
# "lp_apm",
"lp_clkrst",
# "lp_peri",
# "lp_timer",
"lp_wdt",
# "mcpwm0",
# "mem_monitor",
# "modem_lpcon",
# "modem_syscon",
# "otp_debug",
# "parl_io",
# "pau",
# "pcnt",
"pcr",
# "pmu",
# "rmt",
# "rng",
# "rsa",
# "sha",
# "soc_etm",
# "spi0",
# "spi1",
# "spi2",
"systimer",
# "tee",
"timg0",
"timg1",
# "trace",
# "twai0",
"uart0",
"uart1",
# "uhci0",
# "usb_device",
# Additional peripherals defined by us (the developers):
"adc",
"plic",
]

View File

@ -367,3 +367,27 @@ pub mod implementation {
]
}
}
#[cfg(esp32h2)]
pub mod implementation {
//! Analog to digital (ADC) conversion support.
//!
//! This module provides functions for reading analog values from one
//! analog to digital converter available on the ESP32-H2: `ADC1`.
use embedded_hal::adc::Channel;
use super::impl_adc_interface;
pub use crate::analog::{adc::*, ADC1};
use crate::gpio::*;
impl_adc_interface! {
ADC1 [
(Gpio1, 0),
(Gpio2, 1),
(Gpio3, 2),
(Gpio4, 3),
(Gpio5, 4),
]
}
}

View File

@ -1,5 +1,5 @@
#[cfg_attr(esp32, path = "adc/esp32.rs")]
#[cfg_attr(any(esp32c2, esp32c3, esp32c6), path = "adc/riscv.rs")]
#[cfg_attr(riscv, path = "adc/riscv.rs")]
#[cfg_attr(any(esp32s2, esp32s3), path = "adc/xtensa.rs")]
pub mod adc;
#[cfg(dac)]
@ -77,7 +77,7 @@ impl crate::peripheral::Peripheral for DAC2 {
impl crate::peripheral::sealed::Sealed for DAC2 {}
cfg_if::cfg_if! {
if #[cfg(any(esp32, esp32s2, esp32s3))] {
if #[cfg(xtensa)] {
use crate::peripherals::SENS;
pub struct AvailableAnalog {
@ -114,7 +114,7 @@ cfg_if::cfg_if! {
}
cfg_if::cfg_if! {
if #[cfg(any(esp32c2, esp32c3, esp32c6))] {
if #[cfg(riscv)] {
use crate::peripherals::APB_SARADC;
pub struct AvailableAnalog {

View File

@ -0,0 +1,360 @@
use crate::clock::{ApbClock, Clock, CpuClock, PllClock, XtalClock};
extern "C" {
fn ets_update_cpu_frequency(ticks_per_us: u32);
}
const I2C_BBPLL: u8 = 0x66;
const I2C_BBPLL_HOSTID: u8 = 0;
const I2C_BBPLL_OC_REF_DIV: u8 = 2;
const I2C_BBPLL_OC_REF_DIV_MSB: u8 = 3;
const I2C_BBPLL_OC_REF_DIV_LSB: u8 = 0;
const I2C_BBPLL_OC_DIV: u8 = 3;
const I2C_BBPLL_OC_DIV_MSB: u8 = 5;
const I2C_BBPLL_OC_DIV_LSB: u8 = 0;
const I2C_BBPLL_OC_DHREF_SEL: u8 = 5;
const I2C_BBPLL_OC_DHREF_SEL_MSB: u8 = 5;
const I2C_BBPLL_OC_DHREF_SEL_LSB: u8 = 4;
const I2C_BBPLL_OC_DLREF_SEL: u8 = 5;
const I2C_BBPLL_OC_DLREF_SEL_MSB: u8 = 7;
const I2C_BBPLL_OC_DLREF_SEL_LSB: u8 = 6;
const I2C_MST_ANA_CONF0_REG: u32 = 0x600AD800 + 0x18;
const I2C_MST_BBPLL_STOP_FORCE_HIGH: u32 = 1 << 2;
const I2C_MST_BBPLL_STOP_FORCE_LOW: u32 = 1 << 3;
const I2C_MST_BBPLL_CAL_DONE: u32 = 1 << 24;
const MODEM_LPCON_CLK_CONF_FORCE_ON_REG: u32 = DR_REG_MODEM_LPCON_BASE + 0xc;
const MODEM_LPCON_CLK_I2C_MST_FO: u32 = 1 << 2;
// May be needed for enabling I2C clock
const MODEM_LPCON_I2C_CLK_CONF_REG: u32 = DR_REG_MODEM_LPCON_BASE + 0x8;
const MODEM_LPCON_CLK_I2C_SEL_96M: u32 = 1 << 0;
const DR_REG_MODEM_LPCON_BASE: u32 = 0x600AD000;
const MODEM_LPCON_CLK_CONF_REG: u32 = DR_REG_MODEM_LPCON_BASE + 0x8;
const MODEM_LPCON_CLK_I2C_MST_EN: u32 = 1 << 2;
const DR_REG_I2C_ANA_MST_BASE: u32 = 0x600AD800;
const I2C_MST_DATE_REG: u32 = DR_REG_I2C_ANA_MST_BASE + 0x34;
const I2C_MST_ANA_CONF2_REG: u32 = DR_REG_I2C_ANA_MST_BASE + 0x20;
const I2C_MST_ANA_CONF2: u32 = 0x00FFFFFF;
const I2C_MST_CLK_EN: u32 = 1 << 28;
const REGI2C_BBPLL: u8 = 0x66;
const REGI2C_BIAS: u8 = 0x6a;
const REGI2C_PMU_REG: u8 = 0x6d;
const REGI2C_ULP_CAL: u8 = 0x61;
const REGI2C_SAR_I2C: u8 = 0x69;
const REGI2C_BBPLL_DEVICE_EN: u32 = 1 << 9; // (1 << 5) << 4;
const REGI2C_BIAS_DEVICE_EN: u32 = 1 << 8; // (1 << 4) << 4;
const REGI2C_PMU_DEVICE_EN: u32 = 1 << 12; // (1 << 8) << 4;
const REGI2C_ULP_CAL_DEVICE_EN: u32 = 1 << 10; // (1 << 6) << 4;
const REGI2C_SAR_I2C_DEVICE_EN: u32 = 1 << 11; // (1 << 7) << 4;
const REGI2C_RTC_SLAVE_ID_V: u8 = 0xFF;
const REGI2C_RTC_SLAVE_ID_S: u8 = 0;
const REGI2C_RTC_ADDR_V: u8 = 0xFF;
const REGI2C_RTC_ADDR_S: u8 = 8;
const REGI2C_RTC_WR_CNTL_V: u8 = 0x1;
const REGI2C_RTC_WR_CNTL_S: u8 = 24;
const REGI2C_RTC_DATA_V: u8 = 0xFF;
const REGI2C_RTC_DATA_S: u8 = 16;
const I2C_MST_I2C0_CTRL_REG: u32 = DR_REG_I2C_ANA_MST_BASE + 0x0;
const REGI2C_RTC_BUSY: u32 = 1 << 25;
pub(crate) fn esp32h2_rtc_bbpll_configure(_xtal_freq: XtalClock, _pll_freq: PllClock) {
unsafe {
// Enable I2C master clock
(MODEM_LPCON_CLK_CONF_FORCE_ON_REG as *mut u32).write_volatile(
(MODEM_LPCON_CLK_CONF_FORCE_ON_REG as *mut u32).read_volatile()
| MODEM_LPCON_CLK_I2C_MST_FO,
);
// Set I2C clock to 96MHz
(MODEM_LPCON_I2C_CLK_CONF_REG as *mut u32).write_volatile(
(MODEM_LPCON_I2C_CLK_CONF_REG as *mut u32).read_volatile()
| MODEM_LPCON_CLK_I2C_SEL_96M,
);
let i2c_mst_ana_conf0_reg_ptr = I2C_MST_ANA_CONF0_REG as *mut u32;
// BPPLL calibration start
i2c_mst_ana_conf0_reg_ptr.write_volatile(
i2c_mst_ana_conf0_reg_ptr.read_volatile() & !I2C_MST_BBPLL_STOP_FORCE_HIGH,
);
i2c_mst_ana_conf0_reg_ptr.write_volatile(
i2c_mst_ana_conf0_reg_ptr.read_volatile() | I2C_MST_BBPLL_STOP_FORCE_LOW,
);
let oc_ref_div = 0u32;
let oc_div = 1u32;
let oc_dhref_sel = 3u32;
let oc_dlref_sel = 1u32;
regi2c_write_mask(
I2C_BBPLL,
I2C_BBPLL_HOSTID,
I2C_BBPLL_OC_REF_DIV,
I2C_BBPLL_OC_REF_DIV_MSB,
I2C_BBPLL_OC_REF_DIV_LSB,
oc_ref_div as u8,
);
regi2c_write_mask(
I2C_BBPLL,
I2C_BBPLL_HOSTID,
I2C_BBPLL_OC_DIV,
I2C_BBPLL_OC_DIV_MSB,
I2C_BBPLL_OC_DIV_LSB,
oc_div as u8,
);
regi2c_write_mask(
I2C_BBPLL,
I2C_BBPLL_HOSTID,
I2C_BBPLL_OC_DHREF_SEL,
I2C_BBPLL_OC_DHREF_SEL_MSB,
I2C_BBPLL_OC_DHREF_SEL_LSB,
oc_dhref_sel as u8,
);
regi2c_write_mask(
I2C_BBPLL,
I2C_BBPLL_HOSTID,
I2C_BBPLL_OC_DLREF_SEL,
I2C_BBPLL_OC_DLREF_SEL_MSB,
I2C_BBPLL_OC_DLREF_SEL_LSB,
oc_dlref_sel as u8,
);
// WAIT CALIBRATION DONE
while (i2c_mst_ana_conf0_reg_ptr.read_volatile() & I2C_MST_BBPLL_CAL_DONE) == 0 {}
// BBPLL CALIBRATION STOP
i2c_mst_ana_conf0_reg_ptr.write_volatile(
i2c_mst_ana_conf0_reg_ptr.read_volatile() | I2C_MST_BBPLL_STOP_FORCE_HIGH,
);
i2c_mst_ana_conf0_reg_ptr.write_volatile(
i2c_mst_ana_conf0_reg_ptr.read_volatile() & !I2C_MST_BBPLL_STOP_FORCE_LOW,
);
}
}
pub(crate) fn esp32h2_rtc_bbpll_enable() {
let pmu = unsafe { &*crate::peripherals::PMU::PTR };
pmu.imm_hp_ck_power.modify(|_, w| {
w.tie_high_xpd_bb_i2c()
.set_bit()
.tie_high_xpd_bbpll()
.set_bit()
.tie_high_xpd_bbpll_i2c()
.set_bit()
});
pmu.imm_hp_ck_power
.modify(|_, w| w.tie_high_global_bbpll_icg().set_bit());
let pcr = unsafe { &*crate::peripherals::PCR::PTR };
// switch spimem to PLL 64Mhz clock
unsafe {
pcr.mspi_conf.modify(|_, w| w.mspi_clk_sel().bits(0b10));
}
}
pub(crate) fn esp32h2_rtc_update_to_xtal(freq: XtalClock, _div: u8) {
unsafe {
let pcr = &*crate::peripherals::PCR::PTR;
ets_update_cpu_frequency(freq.mhz());
// Set divider from XTAL to APB clock. Need to set divider to 1 (reg. value 0)
// first.
pcr.ahb_freq_conf
.modify(|_, w| w.ahb_div_num().bits(_div - 1));
pcr.cpu_freq_conf
.modify(|_, w| w.cpu_div_num().bits(_div - 1));
// Switch clock source
pcr.sysclk_conf.modify(|_, w| w.soc_clk_sel().bits(0));
clk_ll_bus_update();
}
}
pub(crate) fn esp32h2_rtc_freq_to_pll_mhz(cpu_clock_speed: CpuClock) {
let cpu_divider = 96 / cpu_clock_speed.mhz();
clk_ll_cpu_set_divider(cpu_divider);
let ahb_divider = match cpu_divider {
1 => 3,
2 => 4,
_ => cpu_divider,
};
clk_ll_ahb_set_divider(ahb_divider);
let pcr = unsafe { &*crate::peripherals::PCR::PTR };
unsafe {
pcr.sysclk_conf.modify(|_, w| w.soc_clk_sel().bits(1));
clk_ll_bus_update();
ets_update_cpu_frequency(cpu_clock_speed.mhz());
}
}
pub(crate) fn esp32h2_rtc_apb_freq_update(apb_freq: ApbClock) {
let lp_aon = unsafe { &*crate::peripherals::LP_AON::ptr() };
let value = ((apb_freq.hz() >> 12) & u16::MAX as u32)
| (((apb_freq.hz() >> 12) & u16::MAX as u32) << 16);
lp_aon
.store5
.modify(|_, w| unsafe { w.lp_aon_store5().bits(value) });
}
fn clk_ll_cpu_set_divider(divider: u32) {
assert!(divider >= 1);
unsafe {
let pcr = &*crate::peripherals::PCR::PTR;
pcr.cpu_freq_conf
.modify(|_, w| w.cpu_div_num().bits((divider - 1) as u8));
}
}
fn clk_ll_ahb_set_divider(divider: u32) {
assert!(divider >= 1);
unsafe {
let pcr = &*crate::peripherals::PCR::PTR;
pcr.ahb_freq_conf
.modify(|_, w| w.ahb_div_num().bits((divider - 1) as u8));
}
}
fn clk_ll_bus_update() {
unsafe {
let pcr = &*crate::peripherals::PCR::PTR;
pcr.bus_clk_update
.modify(|_, w| w.bus_clock_update().bit(true));
// reg_get_bit
while pcr.bus_clk_update.read().bus_clock_update().bit_is_set() {}
}
}
fn regi2c_enable_block(block: u8) {
reg_set_bit(MODEM_LPCON_CLK_CONF_REG, MODEM_LPCON_CLK_I2C_MST_EN);
reg_set_bit(I2C_MST_DATE_REG, I2C_MST_CLK_EN);
// Make I2C_MST_ANA_CONF2 in I2C_MST_ANA_CONF2_REG be 0
unsafe {
(I2C_MST_ANA_CONF2_REG as *mut u32).write_volatile(
// (1 << 18)
(I2C_MST_ANA_CONF2_REG as *mut u32).read_volatile() & !(I2C_MST_ANA_CONF2 as u32),
);
}
// Before config I2C register, enable corresponding slave.
match block {
REGI2C_BBPLL => {
reg_set_bit(I2C_MST_ANA_CONF2_REG, REGI2C_BBPLL_DEVICE_EN);
}
REGI2C_BIAS => {
reg_set_bit(I2C_MST_ANA_CONF2_REG, REGI2C_BIAS_DEVICE_EN);
}
REGI2C_PMU_REG => {
reg_set_bit(I2C_MST_ANA_CONF2_REG, REGI2C_PMU_DEVICE_EN);
}
REGI2C_ULP_CAL => {
reg_set_bit(I2C_MST_ANA_CONF2_REG, REGI2C_ULP_CAL_DEVICE_EN);
}
REGI2C_SAR_I2C => {
reg_set_bit(I2C_MST_ANA_CONF2_REG, REGI2C_SAR_I2C_DEVICE_EN);
}
_ => (),
}
}
fn regi2c_disable_block(block: u8) {
match block {
REGI2C_BBPLL => {
reg_clr_bit(I2C_MST_ANA_CONF2_REG, REGI2C_BBPLL_DEVICE_EN);
}
REGI2C_BIAS => {
reg_clr_bit(I2C_MST_ANA_CONF2_REG, REGI2C_BIAS_DEVICE_EN);
}
REGI2C_PMU_REG => {
reg_clr_bit(I2C_MST_ANA_CONF2_REG, REGI2C_PMU_DEVICE_EN);
}
REGI2C_ULP_CAL => {
reg_clr_bit(I2C_MST_ANA_CONF2_REG, REGI2C_ULP_CAL_DEVICE_EN);
}
REGI2C_SAR_I2C => {
reg_clr_bit(I2C_MST_ANA_CONF2_REG, REGI2C_SAR_I2C_DEVICE_EN);
}
_ => (),
}
}
fn reg_set_bit(reg: u32, bit: u32) {
unsafe {
(reg as *mut u32).write_volatile((reg as *mut u32).read_volatile() | bit);
}
}
fn reg_clr_bit(reg: u32, bit: u32) {
unsafe {
(reg as *mut u32).write_volatile((reg as *mut u32).read_volatile() & !bit);
}
}
fn reg_write(reg: u32, v: u32) {
unsafe {
(reg as *mut u32).write_volatile(v);
}
}
fn reg_get_bit(reg: u32, b: u32) -> u32 {
unsafe { (reg as *mut u32).read_volatile() & b }
}
fn reg_get_field(reg: u32, s: u32, v: u32) -> u32 {
unsafe { ((reg as *mut u32).read_volatile() >> s) & v }
}
pub(crate) fn regi2c_write_mask(block: u8, _host_id: u8, reg_add: u8, msb: u8, lsb: u8, data: u8) {
assert!(msb - lsb < 8);
regi2c_enable_block(block);
// Read the i2c bus register
let mut temp: u32 = ((block as u32 & REGI2C_RTC_SLAVE_ID_V as u32)
<< REGI2C_RTC_SLAVE_ID_S as u32)
| (reg_add as u32 & REGI2C_RTC_ADDR_V as u32) << REGI2C_RTC_ADDR_S as u32;
reg_write(I2C_MST_I2C0_CTRL_REG, temp);
while reg_get_bit(I2C_MST_I2C0_CTRL_REG, REGI2C_RTC_BUSY) != 0 {}
temp = reg_get_field(
I2C_MST_I2C0_CTRL_REG,
REGI2C_RTC_DATA_S as u32,
REGI2C_RTC_DATA_V as u32,
);
// Write the i2c bus register
temp &= (!(0xFFFFFFFF << lsb)) | (0xFFFFFFFF << (msb + 1));
temp =
((data as u32 & (!(0xFFFFFFFF << (msb as u32 - lsb as u32 + 1)))) << (lsb as u32)) | temp;
temp = ((block as u32 & REGI2C_RTC_SLAVE_ID_V as u32) << REGI2C_RTC_SLAVE_ID_S as u32)
| ((reg_add as u32 & REGI2C_RTC_ADDR_V as u32) << REGI2C_RTC_ADDR_S as u32)
| ((0x1 & REGI2C_RTC_WR_CNTL_V as u32) << REGI2C_RTC_WR_CNTL_S as u32)
| ((temp & REGI2C_RTC_DATA_V as u32) << REGI2C_RTC_DATA_S as u32);
reg_write(I2C_MST_I2C0_CTRL_REG, temp);
while reg_get_bit(I2C_MST_I2C0_CTRL_REG, REGI2C_RTC_BUSY) != 0 {}
regi2c_disable_block(block);
}

View File

@ -10,6 +10,7 @@ use crate::{
#[cfg_attr(esp32c2, path = "clocks_ll/esp32c2.rs")]
#[cfg_attr(esp32c3, path = "clocks_ll/esp32c3.rs")]
#[cfg_attr(esp32c6, path = "clocks_ll/esp32c6.rs")]
#[cfg_attr(esp32h2, path = "clocks_ll/esp32h2.rs")]
#[cfg_attr(esp32s2, path = "clocks_ll/esp32s2.rs")]
#[cfg_attr(esp32s3, path = "clocks_ll/esp32s3.rs")]
pub(crate) mod clocks_ll;
@ -30,6 +31,8 @@ pub trait Clock {
#[derive(Debug, Clone, Copy)]
pub enum CpuClock {
Clock80MHz,
#[cfg(esp32h2)]
Clock96MHz,
#[cfg(esp32c2)]
Clock120MHz,
#[cfg(not(esp32c2))]
@ -43,6 +46,8 @@ impl Clock for CpuClock {
fn frequency(&self) -> HertzU32 {
match self {
CpuClock::Clock80MHz => HertzU32::MHz(80),
#[cfg(esp32h2)]
CpuClock::Clock96MHz => HertzU32::MHz(96),
#[cfg(esp32c2)]
CpuClock::Clock120MHz => HertzU32::MHz(120),
#[cfg(not(esp32c2))]
@ -60,7 +65,7 @@ pub(crate) enum XtalClock {
RtcXtalFreq24M,
#[cfg(any(esp32, esp32c2))]
RtcXtalFreq26M,
#[cfg(any(esp32c3, esp32s3))]
#[cfg(any(esp32c3, esp32s3, esp32h2))]
RtcXtalFreq32M,
RtcXtalFreq40M,
RtcXtalFreqOther(u32),
@ -73,7 +78,7 @@ impl Clock for XtalClock {
XtalClock::RtcXtalFreq24M => HertzU32::MHz(24),
#[cfg(any(esp32, esp32c2))]
XtalClock::RtcXtalFreq26M => HertzU32::MHz(26),
#[cfg(any(esp32c3, esp32s3))]
#[cfg(any(esp32c3, esp32s3, esp32h2))]
XtalClock::RtcXtalFreq32M => HertzU32::MHz(32),
XtalClock::RtcXtalFreq40M => HertzU32::MHz(40),
XtalClock::RtcXtalFreqOther(mhz) => HertzU32::MHz(*mhz),
@ -429,6 +434,58 @@ impl<'d> ClockControl<'d> {
}
}
#[cfg(esp32h2)]
impl<'d> ClockControl<'d> {
/// Use what is considered the default settings after boot.
#[allow(unused)]
pub fn boot_defaults(
clock_control: impl Peripheral<P = SystemClockControl> + 'd,
) -> ClockControl<'d> {
ClockControl {
_private: clock_control.into_ref(),
desired_rates: RawClocks {
cpu_clock: HertzU32::MHz(96),
apb_clock: HertzU32::MHz(32),
xtal_clock: HertzU32::MHz(32),
i2c_clock: HertzU32::MHz(32),
},
}
}
/// Configure the CPU clock speed.
#[allow(unused)]
pub fn configure(
clock_control: impl Peripheral<P = SystemClockControl> + 'd,
cpu_clock_speed: CpuClock,
) -> ClockControl<'d> {
let apb_freq;
let xtal_freq = XtalClock::RtcXtalFreqOther(32);
let pll_freq = PllClock::Pll320MHz;
if cpu_clock_speed.mhz() <= xtal_freq.mhz() {
apb_freq = ApbClock::ApbFreqOther(cpu_clock_speed.mhz());
clocks_ll::esp32h2_rtc_update_to_xtal(xtal_freq, 1);
clocks_ll::esp32h2_rtc_apb_freq_update(apb_freq);
} else {
apb_freq = ApbClock::ApbFreqOther(32);
clocks_ll::esp32h2_rtc_bbpll_enable();
clocks_ll::esp32h2_rtc_bbpll_configure(xtal_freq, pll_freq);
clocks_ll::esp32h2_rtc_freq_to_pll_mhz(cpu_clock_speed);
clocks_ll::esp32h2_rtc_apb_freq_update(apb_freq);
}
ClockControl {
_private: clock_control.into_ref(),
desired_rates: RawClocks {
cpu_clock: cpu_clock_speed.frequency(),
apb_clock: apb_freq.frequency(),
xtal_clock: xtal_freq.frequency(),
i2c_clock: HertzU32::MHz(32),
},
}
}
}
#[cfg(esp32s2)]
impl<'d> ClockControl<'d> {
/// Use what is considered the default settings after boot.

View File

@ -262,7 +262,7 @@ impl InteruptStatusRegisterAccess for SingleCoreInteruptStatusRegisterAccessBank
// interrupt enable bit see
// https://github.com/espressif/esp-idf/blob/c04803e88b871a4044da152dfb3699cf47354d18/components/hal/esp32s3/include/hal/gpio_ll.h#L32
// Treating it as SingleCore in the gpio macro makes this work.
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32s2, esp32s3)))]
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s2, esp32s3)))]
impl InteruptStatusRegisterAccess for DualCoreInteruptStatusRegisterAccessBank0 {
fn pro_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_int.read().bits()
@ -285,7 +285,7 @@ impl InteruptStatusRegisterAccess for DualCoreInteruptStatusRegisterAccessBank0
// interrupt enable bit see
// https://github.com/espressif/esp-idf/blob/c04803e88b871a4044da152dfb3699cf47354d18/components/hal/esp32s3/include/hal/gpio_ll.h#L32
// Treating it as SingleCore in the gpio macro makes this work.
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32s2, esp32s3)))]
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s2, esp32s3)))]
impl InteruptStatusRegisterAccess for DualCoreInteruptStatusRegisterAccessBank1 {
fn pro_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_int1.read().bits()
@ -449,7 +449,7 @@ impl BankGpioRegisterAccess for Bank0GpioRegisterAccess {
}
}
#[cfg(not(any(esp32c2, esp32c3, esp32c6)))]
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
impl BankGpioRegisterAccess for Bank1GpioRegisterAccess {
fn write_out_en_clear(word: u32) {
unsafe { &*GPIO::PTR }
@ -1677,7 +1677,7 @@ pub fn enable_iomux_clk_gate() {
}
}
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32s2)))]
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s2)))]
#[doc(hidden)]
#[macro_export]
macro_rules! analog {
@ -1795,7 +1795,7 @@ macro_rules! analog {
}
}
#[cfg(any(esp32c2, esp32c3, esp32c6))]
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2))]
#[doc(hidden)]
#[macro_export]
macro_rules! analog {

View File

@ -9,6 +9,7 @@
//! - [esp32c2-hal]
//! - [esp32c3-hal]
//! - [esp32c6-hal]
//! - [esp32h2-hal]
//! - [esp32s2-hal]
//! - [esp32s3-hal]
//!
@ -17,6 +18,7 @@
//! [esp32c2-hal]: https://github.com/esp-rs/esp-hal/tree/main/esp32c2-hal
//! [esp32c3-hal]: https://github.com/esp-rs/esp-hal/tree/main/esp32c3-hal
//! [esp32c6-hal]: https://github.com/esp-rs/esp-hal/tree/main/esp32c6-hal
//! [esp32h2-hal]: https://github.com/esp-rs/esp-hal/tree/main/esp32h2-hal
//! [esp32s2-hal]: https://github.com/esp-rs/esp-hal/tree/main/esp32s2-hal
//! [esp32s3-hal]: https://github.com/esp-rs/esp-hal/tree/main/esp32s3-hal
@ -42,6 +44,8 @@ pub use xtensa_lx_rt::{self, entry};
pub use self::analog::adc::implementation as adc;
#[cfg(dac)]
pub use self::analog::dac::implementation as dac;
#[cfg(any(xtensa, all(riscv, systimer)))]
pub use self::delay::Delay;
#[cfg(gdma)]
pub use self::dma::gdma;
#[cfg(pdma)]
@ -58,6 +62,7 @@ pub use self::rtc_cntl::{Rtc, Rwdt};
pub use self::soc::cpu_control;
#[cfg(efuse)]
pub use self::soc::efuse;
pub use self::soc::peripherals;
#[cfg(any(spi0, spi1, spi2, spi3))]
pub use self::spi::Spi;
#[cfg(any(timg0, timg1))]
@ -66,7 +71,6 @@ pub use self::timer::Timer;
pub use self::uart::Uart;
#[cfg(usb_device)]
pub use self::usb_serial_jtag::UsbSerialJtag;
pub use self::{delay::Delay, soc::peripherals};
#[cfg(aes)]
pub mod aes;
@ -75,6 +79,7 @@ pub mod analog;
#[cfg(assist_debug)]
pub mod assist_debug;
pub mod clock;
#[cfg(any(xtensa, all(riscv, systimer)))]
pub mod delay;
#[cfg(any(gdma, pdma))]
pub mod dma;

View File

@ -1,16 +1,16 @@
use embedded_hal::watchdog::{Watchdog, WatchdogDisable, WatchdogEnable};
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
use fugit::HertzU32;
use fugit::MicrosDurationU64;
pub use self::rtc::SocResetReason;
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
use crate::clock::XtalClock;
#[cfg(not(esp32))]
use crate::efuse::Efuse;
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
use crate::peripherals::{LP_TIMER, LP_WDT};
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
use crate::peripherals::{RTC_CNTL, TIMG0};
use crate::{
clock::Clock,
@ -19,20 +19,21 @@ use crate::{
Cpu,
};
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
type RtcCntl = crate::peripherals::LP_CLKRST;
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
type RtcCntl = crate::peripherals::RTC_CNTL;
#[cfg_attr(esp32, path = "rtc/esp32.rs")]
#[cfg_attr(esp32c2, path = "rtc/esp32c2.rs")]
#[cfg_attr(esp32c3, path = "rtc/esp32c3.rs")]
#[cfg_attr(esp32c6, path = "rtc/esp32c6.rs")]
#[cfg_attr(esp32h2, path = "rtc/esp32h2.rs")]
#[cfg_attr(esp32s2, path = "rtc/esp32s2.rs")]
#[cfg_attr(esp32s3, path = "rtc/esp32s3.rs")]
mod rtc;
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
pub use rtc::RtcClock;
extern "C" {
@ -43,7 +44,7 @@ extern "C" {
pub fn software_reset();
}
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
#[allow(unused)]
#[derive(Debug, Clone, Copy)]
/// RTC SLOW_CLK frequency values
@ -54,20 +55,20 @@ pub(crate) enum RtcFastClock {
RtcFastClock8m = 1,
}
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
impl Clock for RtcFastClock {
fn frequency(&self) -> HertzU32 {
match self {
RtcFastClock::RtcFastClockXtalD4 => HertzU32::Hz(40_000_000 / 4),
#[cfg(any(esp32, esp32s2))]
RtcFastClock::RtcFastClock8m => HertzU32::Hz(8_500_000),
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
RtcFastClock::RtcFastClock8m => HertzU32::Hz(17_500_000),
}
}
}
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
#[allow(unused)]
#[derive(Debug, Clone, Copy)]
/// RTC SLOW_CLK frequency values
@ -80,7 +81,7 @@ pub(crate) enum RtcSlowClock {
RtcSlowClock8mD256 = 2,
}
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
impl Clock for RtcSlowClock {
fn frequency(&self) -> HertzU32 {
match self {
@ -100,7 +101,7 @@ impl Clock for RtcSlowClock {
}
#[allow(unused)]
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
#[derive(Debug, Clone, Copy)]
/// Clock source to be calibrated using rtc_clk_cal function
pub(crate) enum RtcCalSel {
@ -118,7 +119,7 @@ pub(crate) enum RtcCalSel {
pub struct Rtc<'d> {
_inner: PeripheralRef<'d, RtcCntl>,
pub rwdt: Rwdt,
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
pub swd: Swd,
}
@ -130,22 +131,22 @@ impl<'d> Rtc<'d> {
Self {
_inner: rtc_cntl.into_ref(),
rwdt: Rwdt::default(),
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
swd: Swd::new(),
}
}
// TODO: implement for ESP32-C6
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
pub fn estimate_xtal_frequency(&mut self) -> u32 {
RtcClock::estimate_xtal_frequency()
}
/// read the current value of the rtc time registers.
pub fn get_time_raw(&self) -> u64 {
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*RTC_CNTL::ptr() };
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let rtc_cntl = unsafe { &*LP_TIMER::ptr() };
#[cfg(esp32)]
@ -168,7 +169,7 @@ impl<'d> Rtc<'d> {
let l = rtc_cntl.time_low0.read().timer_value0_low().bits();
(l, h)
};
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let (l, h) = {
rtc_cntl.update.write(|w| w.main_timer_update().set_bit());
let h = rtc_cntl.main_buf0_high.read().main_timer_buf0_high().bits();
@ -189,11 +190,11 @@ impl<'d> Rtc<'d> {
}
}
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
/// RTC Watchdog Timer
pub struct RtcClock;
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
/// RTC Watchdog Timer driver
impl RtcClock {
const CAL_FRACT: u32 = 19;
@ -210,7 +211,7 @@ impl RtcClock {
///
/// When 8MHz/256 divided output is not needed, the divider should be
/// disabled to reduce power consumption.
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
fn enable_8m(clk_8m_en: bool, d256_en: bool) {
let rtc_cntl = unsafe { &*RTC_CNTL::PTR };
@ -267,7 +268,7 @@ impl RtcClock {
}
/// Get the RTC_SLOW_CLK source
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
fn get_slow_freq() -> RtcSlowClock {
let rtc_cntl = unsafe { &*RTC_CNTL::PTR };
let slow_freq = rtc_cntl.clk_conf.read().ana_clk_rtc_sel().bits();
@ -280,7 +281,7 @@ impl RtcClock {
}
/// Select source for RTC_SLOW_CLK
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
fn set_slow_freq(slow_freq: RtcSlowClock) {
unsafe {
let rtc_cntl = &*RTC_CNTL::PTR;
@ -309,7 +310,7 @@ impl RtcClock {
}
/// Select source for RTC_FAST_CLK
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
fn set_fast_freq(fast_freq: RtcFastClock) {
unsafe {
let rtc_cntl = &*RTC_CNTL::PTR;
@ -327,7 +328,7 @@ impl RtcClock {
/// Calibration of RTC_SLOW_CLK is performed using a special feature of
/// TIMG0. This feature counts the number of XTAL clock cycles within a
/// given number of RTC_SLOW_CLK cycles.
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
fn calibrate_internal(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
// Except for ESP32, choosing RTC_CAL_RTC_MUX results in calibration of
// the 150k RTC clock (90k on ESP32-S2) regardless of the currently selected
@ -502,7 +503,7 @@ impl RtcClock {
match RtcClock::get_slow_freq() {
RtcSlowClock::RtcSlowClockRtc => RtcCalSel::RtcCalRtcMux,
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
RtcSlowClock::RtcSlowClock8mD256 => RtcCalSel::RtcCal8mD256,
},
1024,
@ -515,7 +516,7 @@ impl RtcClock {
}
// TODO: implement for ESP32-C6
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
fn estimate_xtal_frequency() -> u32 {
// Number of 8M/256 clock cycles to use for XTAL frequency estimation.
const XTAL_FREQ_EST_CYCLES: u32 = 10;
@ -572,9 +573,9 @@ impl Default for Rwdt {
/// RTC Watchdog Timer driver
impl Rwdt {
pub fn listen(&mut self) {
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*RTC_CNTL::PTR };
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let rtc_cntl = unsafe { &*LP_WDT::PTR };
self.stg0_action = RwdtStageAction::RwdtStageActionInterrupt;
@ -597,9 +598,9 @@ impl Rwdt {
}
pub fn unlisten(&mut self) {
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*RTC_CNTL::PTR };
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let rtc_cntl = unsafe { &*LP_WDT::PTR };
self.stg0_action = RwdtStageAction::RwdtStageActionResetRtc;
@ -622,9 +623,9 @@ impl Rwdt {
}
pub fn clear_interrupt(&mut self) {
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*RTC_CNTL::PTR };
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let rtc_cntl = unsafe { &*LP_WDT::PTR };
self.set_write_protection(false);
@ -638,9 +639,9 @@ impl Rwdt {
}
pub fn is_interrupt_set(&self) -> bool {
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*RTC_CNTL::PTR };
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let rtc_cntl = unsafe { &*LP_WDT::PTR };
cfg_if::cfg_if! {
@ -654,10 +655,11 @@ impl Rwdt {
/// Enable/disable write protection for WDT registers
fn set_write_protection(&mut self, enable: bool) {
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*RTC_CNTL::PTR };
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let rtc_cntl = unsafe { &*LP_WDT::PTR };
let wkey = if enable { 0u32 } else { 0x50D8_3AA1 };
rtc_cntl.wdtwprotect.write(|w| unsafe { w.bits(wkey) });
@ -666,9 +668,9 @@ impl Rwdt {
impl WatchdogDisable for Rwdt {
fn disable(&mut self) {
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*RTC_CNTL::PTR };
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let rtc_cntl = unsafe { &*LP_WDT::PTR };
self.set_write_protection(false);
@ -689,9 +691,9 @@ impl WatchdogEnable for Rwdt {
where
T: Into<Self::Time>,
{
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*RTC_CNTL::PTR };
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let rtc_cntl = unsafe { &*LP_WDT::PTR };
let timeout_raw = (period.into().to_millis() * (RtcClock::cycles_to_1ms() as u64)) as u32;
@ -703,13 +705,13 @@ impl WatchdogEnable for Rwdt {
.wdtconfig1
.modify(|_, w| w.wdt_stg0_hold().bits(timeout_raw));
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
(&*LP_WDT::PTR).config1.modify(|_, w| {
w.wdt_stg0_hold()
.bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier()))
});
#[cfg(not(any(esp32, esp32c6)))]
#[cfg(not(any(esp32, esp32c6, esp32h2)))]
rtc_cntl.wdtconfig1.modify(|_, w| {
w.wdt_stg0_hold()
.bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier()))
@ -739,9 +741,9 @@ impl WatchdogEnable for Rwdt {
impl Watchdog for Rwdt {
fn feed(&mut self) {
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*RTC_CNTL::PTR };
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let rtc_cntl = unsafe { &*LP_WDT::PTR };
self.set_write_protection(false);
@ -750,11 +752,11 @@ impl Watchdog for Rwdt {
}
}
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
/// Super Watchdog
pub struct Swd;
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
/// Super Watchdog driver
impl Swd {
pub fn new() -> Self {
@ -763,14 +765,14 @@ impl Swd {
/// Enable/disable write protection for WDT registers
fn set_write_protection(&mut self, enable: bool) {
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*RTC_CNTL::PTR };
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let rtc_cntl = unsafe { &*LP_WDT::PTR };
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
let wkey = if enable { 0u32 } else { 0x8F1D_312A };
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let wkey = if enable { 0u32 } else { 0x50D8_3AA1 };
rtc_cntl
@ -779,12 +781,12 @@ impl Swd {
}
}
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
impl WatchdogDisable for Swd {
fn disable(&mut self) {
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
let rtc_cntl = unsafe { &*RTC_CNTL::PTR };
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let rtc_cntl = unsafe { &*LP_WDT::PTR };
self.set_write_protection(false);
@ -801,13 +803,11 @@ pub fn get_reset_reason(cpu: Cpu) -> Option<SocResetReason> {
}
pub fn get_wakeup_cause() -> SleepSource {
// FIXME: check s_light_sleep_wakeup
// https://github.com/espressif/esp-idf/blob/afbdb0f3ef195ab51690a64e22bfb8a5cd487914/components/esp_hw_support/sleep_modes.c#L1394
if get_reset_reason(Cpu::ProCpu).unwrap() != SocResetReason::CoreDeepSleep {
return SleepSource::Undefined;
}
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let wakeup_cause = WakeupReason::from_bits_retain(unsafe {
(&*crate::peripherals::PMU::PTR)
.slp_wakeup_status0
@ -815,7 +815,7 @@ pub fn get_wakeup_cause() -> SleepSource {
.wakeup_cause()
.bits()
});
#[cfg(not(any(esp32, esp32c6)))]
#[cfg(not(any(esp32, esp32c6, esp32h2)))]
let wakeup_cause = WakeupReason::from_bits_retain(unsafe {
(&*RTC_CNTL::PTR)
.slp_wakeup_cause

View File

@ -0,0 +1,640 @@
use fugit::HertzU32;
use strum::FromRepr;
use crate::{
clock::{clocks_ll::regi2c_write_mask, Clock, XtalClock},
peripherals::{LP_AON, LP_CLKRST, PCR, PMU, TIMG0},
};
const I2C_PMU: u8 = 0x6d;
const I2C_PMU_HOSTID: u8 = 0;
const I2C_PMU_EN_I2C_RTC_DREG: u8 = 8;
const I2C_PMU_EN_I2C_RTC_DREG_MSB: u8 = 0;
const I2C_PMU_EN_I2C_RTC_DREG_LSB: u8 = 0;
const I2C_PMU_EN_I2C_DIG_DREG: u8 = 8;
const I2C_PMU_EN_I2C_DIG_DREG_MSB: u8 = 1;
const I2C_PMU_EN_I2C_DIG_DREG_LSB: u8 = 1;
const I2C_PMU_EN_I2C_RTC_DREG_SLP: u8 = 8;
const I2C_PMU_EN_I2C_RTC_DREG_SLP_MSB: u8 = 2;
const I2C_PMU_EN_I2C_RTC_DREG_SLP_LSB: u8 = 2;
const I2C_PMU_EN_I2C_DIG_DREG_SLP: u8 = 8;
const I2C_PMU_EN_I2C_DIG_DREG_SLP_MSB: u8 = 3;
const I2C_PMU_EN_I2C_DIG_DREG_SLP_LSB: u8 = 3;
const I2C_PMU_OR_XPD_RTC_REG: u8 = 8;
const I2C_PMU_OR_XPD_RTC_REG_MSB: u8 = 4;
const I2C_PMU_OR_XPD_RTC_REG_LSB: u8 = 4;
const I2C_PMU_OR_XPD_DIG_REG: u8 = 8;
const I2C_PMU_OR_XPD_DIG_REG_MSB: u8 = 5;
const I2C_PMU_OR_XPD_DIG_REG_LSB: u8 = 5;
const I2C_PMU_OR_XPD_TRX: u8 = 15;
const I2C_PMU_OR_XPD_TRX_MSB: u8 = 2;
const I2C_PMU_OR_XPD_TRX_LSB: u8 = 2;
const DR_REG_PMU_BASE: u32 = 0x600B0000;
const PMU_POWER_PD_TOP_CNTL_REG: u32 = DR_REG_PMU_BASE + 0xf4;
const PMU_POWER_PD_HPAON_CNTL_REG: u32 = DR_REG_PMU_BASE + 0xf8;
const PMU_POWER_PD_HPCPU_CNTL_REG: u32 = DR_REG_PMU_BASE + 0xfc;
const PMU_POWER_PD_HPPERI_RESERVE_REG: u32 = DR_REG_PMU_BASE + 0x100;
const PMU_POWER_PD_HPWIFI_CNTL_REG: u32 = DR_REG_PMU_BASE + 0x104;
const PMU_POWER_PD_LPPERI_CNTL_REG: u32 = DR_REG_PMU_BASE + 0x108;
pub(crate) fn init() {
// * No peripheral reg i2c power up required on the target */
unsafe {
regi2c_write_mask(
I2C_PMU,
I2C_PMU_HOSTID,
I2C_PMU_EN_I2C_RTC_DREG,
I2C_PMU_EN_I2C_RTC_DREG_MSB,
I2C_PMU_EN_I2C_RTC_DREG_LSB,
0,
);
regi2c_write_mask(
I2C_PMU,
I2C_PMU_HOSTID,
I2C_PMU_EN_I2C_DIG_DREG,
I2C_PMU_EN_I2C_DIG_DREG_MSB,
I2C_PMU_EN_I2C_DIG_DREG_LSB,
0,
);
regi2c_write_mask(
I2C_PMU,
I2C_PMU_HOSTID,
I2C_PMU_EN_I2C_RTC_DREG_SLP,
I2C_PMU_EN_I2C_RTC_DREG_SLP_MSB,
I2C_PMU_EN_I2C_RTC_DREG_SLP_LSB,
0,
);
regi2c_write_mask(
I2C_PMU,
I2C_PMU_HOSTID,
I2C_PMU_EN_I2C_DIG_DREG_SLP,
I2C_PMU_EN_I2C_DIG_DREG_SLP_MSB,
I2C_PMU_EN_I2C_DIG_DREG_SLP_LSB,
0,
);
regi2c_write_mask(
I2C_PMU,
I2C_PMU_HOSTID,
I2C_PMU_OR_XPD_RTC_REG,
I2C_PMU_OR_XPD_RTC_REG_MSB,
I2C_PMU_OR_XPD_RTC_REG_LSB,
0,
);
regi2c_write_mask(
I2C_PMU,
I2C_PMU_HOSTID,
I2C_PMU_OR_XPD_DIG_REG,
I2C_PMU_OR_XPD_DIG_REG_MSB,
I2C_PMU_OR_XPD_DIG_REG_LSB,
0,
);
regi2c_write_mask(
I2C_PMU,
I2C_PMU_HOSTID,
I2C_PMU_OR_XPD_TRX,
I2C_PMU_OR_XPD_TRX_MSB,
I2C_PMU_OR_XPD_TRX_LSB,
0,
);
(PMU_POWER_PD_TOP_CNTL_REG as *mut u32).write_volatile(0);
(PMU_POWER_PD_HPAON_CNTL_REG as *mut u32).write_volatile(0);
(PMU_POWER_PD_HPCPU_CNTL_REG as *mut u32).write_volatile(0);
(PMU_POWER_PD_HPPERI_RESERVE_REG as *mut u32).write_volatile(0);
(PMU_POWER_PD_HPWIFI_CNTL_REG as *mut u32).write_volatile(0);
(PMU_POWER_PD_LPPERI_CNTL_REG as *mut u32).write_volatile(0);
let pmu = &*PMU::ptr();
pmu.hp_active_hp_regulator0
.modify(|_, w| w.hp_active_hp_regulator_dbias().bits(25));
pmu.hp_sleep_lp_regulator0
.modify(|_, w| w.hp_sleep_lp_regulator_dbias().bits(26));
pmu.slp_wakeup_cntl5
.modify(|_, w| w.lp_ana_wait_target().bits(15));
pmu.slp_wakeup_cntl7
.modify(|_, w| w.ana_wait_target().bits(1700));
}
}
pub(crate) fn configure_clock() {
assert!(matches!(
RtcClock::get_xtal_freq(),
XtalClock::RtcXtalFreq32M
));
RtcClock::set_fast_freq(RtcFastClock::RtcFastClockRcFast);
let cal_val = loop {
RtcClock::set_slow_freq(RtcSlowClock::RtcSlowClockRcSlow);
let res = RtcClock::calibrate(RtcCalSel::RtcCalRtcMux, 1024);
if res != 0 {
break res;
}
};
unsafe {
let lp_aon = &*LP_AON::ptr();
lp_aon.store1.modify(|_, w| w.bits(cal_val));
}
}
// Terminology:
//
// CPU Reset: Reset CPU core only, once reset done, CPU will execute from
// reset vector
// Core Reset: Reset the whole digital system except RTC sub-system
// System Reset: Reset the whole digital system, including RTC sub-system
// Chip Reset: Reset the whole chip, including the analog part
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromRepr)]
pub enum SocResetReason {
/// Power on reset
///
/// In ESP-IDF this value (0x01) can *also* be `ChipBrownOut` or
/// `ChipSuperWdt`, however that is not really compatible with Rust-style
/// enums.
ChipPowerOn = 0x01,
/// Software resets the digital core by RTC_CNTL_SW_SYS_RST
CoreSw = 0x03,
/// Deep sleep reset the digital core
CoreDeepSleep = 0x05,
/// Main watch dog 0 resets digital core
CoreMwdt0 = 0x07,
/// Main watch dog 1 resets digital core
CoreMwdt1 = 0x08,
/// RTC watch dog resets digital core
CoreRtcWdt = 0x09,
/// Main watch dog 0 resets CPU 0
Cpu0Mwdt0 = 0x0B,
/// Software resets CPU 0 by RTC_CNTL_SW_PROCPU_RST
Cpu0Sw = 0x0C,
/// RTC watch dog resets CPU 0
Cpu0RtcWdt = 0x0D,
/// VDD voltage is not stable and resets the digital core
SysBrownOut = 0x0F,
/// RTC watch dog resets digital core and rtc module
SysRtcWdt = 0x10,
/// Main watch dog 1 resets CPU 0
Cpu0Mwdt1 = 0x11,
/// Super watch dog resets the digital core and rtc module
SysSuperWdt = 0x12,
/// Glitch on clock resets the digital core and rtc module
SysClkGlitch = 0x13,
/// eFuse CRC error resets the digital core
CoreEfuseCrc = 0x14,
/// USB UART resets the digital core
CoreUsbUart = 0x15,
/// USB JTAG resets the digital core
CoreUsbJtag = 0x16,
/// Glitch on power resets the digital core
CorePwrGlitch = 0x17,
}
/// RTC SLOW_CLK frequency values
#[derive(Debug, Clone, Copy)]
pub(crate) enum RtcFastClock {
/// Select RC_FAST_CLK as RTC_FAST_CLK source
RtcFastClockRcFast = 0,
/// Select XTAL_D2_CLK as RTC_FAST_CLK source
RtcFastClockXtalD2 = 1,
}
impl Clock for RtcFastClock {
fn frequency(&self) -> HertzU32 {
match self {
RtcFastClock::RtcFastClockXtalD2 => HertzU32::Hz(16_000_000),
RtcFastClock::RtcFastClockRcFast => HertzU32::Hz(8_000_000),
}
}
}
extern "C" {
fn ets_delay_us(us: u32);
}
/// RTC SLOW_CLK frequency values
#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) enum RtcSlowClock {
/// Select RC_SLOW_CLK as RTC_SLOW_CLK source
RtcSlowClockRcSlow = 0,
/// Select XTAL32K_CLK as RTC_SLOW_CLK source
RtcSlowClock32kXtal = 1,
/// Select RC32K_CLK as RTC_SLOW_CLK source
RtcSlowClock32kRc = 2,
/// Select OSC_SLOW_CLK (external slow clock) as RTC_SLOW_CLK source
RtcSlowOscSlow = 3,
}
impl Clock for RtcSlowClock {
fn frequency(&self) -> HertzU32 {
match self {
RtcSlowClock::RtcSlowClockRcSlow => HertzU32::Hz(150_000),
RtcSlowClock::RtcSlowClock32kXtal => HertzU32::Hz(32_768),
RtcSlowClock::RtcSlowClock32kRc => HertzU32::Hz(32_768),
RtcSlowClock::RtcSlowOscSlow => HertzU32::Hz(32_768),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
/// Clock source to be calibrated using rtc_clk_cal function
pub(crate) enum RtcCalSel {
/// Currently selected RTC SLOW_CLK
RtcCalRtcMux = -1,
/// Internal 150kHz RC oscillator
RtcCalRcSlow = 0,
/// External 32kHz XTAL, as one type of 32k clock
RtcCal32kXtal = 1,
/// Internal 32kHz RC oscillator, as one type of 32k clock
RtcCal32kRc = 2,
/// External slow clock signal input by lp_pad_gpio0, as one type of 32k
/// clock
RtcCal32kOscSlow = 3,
/// Internal 20MHz RC oscillator
RtcCalRcFast,
}
#[derive(Clone)]
pub(crate) enum RtcCaliClkSel {
CaliClkRcSlow = 0,
CaliClkRcFast = 1,
CaliClk32k = 2,
}
/// RTC Watchdog Timer
pub struct RtcClock;
/// RTC Watchdog Timer driver
impl RtcClock {
const CAL_FRACT: u32 = 19;
/// Calculate the necessary RTC_SLOW_CLK cycles to complete 1 millisecond.
fn get_xtal_freq() -> XtalClock {
let xtal_freq_reg = unsafe { &*LP_AON::PTR }.store4.read().bits();
// Values of RTC_XTAL_FREQ_REG and RTC_APB_FREQ_REG are stored as two copies in
// lower and upper 16-bit halves. These are the routines to work with such a
// representation.
let clk_val_is_valid = |val| {
(val & 0xffffu32) == ((val >> 16u32) & 0xffffu32) && val != 0u32 && val != u32::MAX
};
let reg_val_to_clk_val = |val| val & u16::MAX as u32;
if !clk_val_is_valid(xtal_freq_reg) {
return XtalClock::RtcXtalFreq32M;
}
match reg_val_to_clk_val(xtal_freq_reg) {
32 => XtalClock::RtcXtalFreq32M,
other => XtalClock::RtcXtalFreqOther(other),
}
}
fn set_fast_freq(fast_freq: RtcFastClock) {
// components/hal/esp32s2/include/hal/clk_tree_ll.h
unsafe {
let lp_clkrst = &*LP_CLKRST::PTR;
lp_clkrst.lp_clk_conf.modify(|_, w| {
w.fast_clk_sel().bits(match fast_freq {
RtcFastClock::RtcFastClockRcFast => 0b00,
RtcFastClock::RtcFastClockXtalD2 => 0b01,
})
});
ets_delay_us(3);
}
}
fn set_slow_freq(slow_freq: RtcSlowClock) {
unsafe {
let lp_clkrst = &*LP_CLKRST::PTR;
lp_clkrst
.lp_clk_conf
.modify(|_, w| w.slow_clk_sel().bits(slow_freq as u8));
lp_clkrst.clk_to_hp.modify(|_, w| {
w.icg_hp_xtal32k()
.bit(match slow_freq {
RtcSlowClock::RtcSlowClock32kXtal => true,
_ => false,
})
.icg_hp_xtal32k()
.bit(match slow_freq {
RtcSlowClock::RtcSlowClock32kXtal => true,
_ => false,
})
});
}
}
/// Get the RTC_SLOW_CLK source
pub(crate) fn get_slow_freq() -> RtcSlowClock {
let lp_clrst = unsafe { &*LP_CLKRST::ptr() };
let slow_freq = lp_clrst.lp_clk_conf.read().slow_clk_sel().bits();
match slow_freq {
0 => RtcSlowClock::RtcSlowClockRcSlow,
1 => RtcSlowClock::RtcSlowClock32kXtal,
2 => RtcSlowClock::RtcSlowClock32kRc,
3 => RtcSlowClock::RtcSlowOscSlow,
_ => unreachable!(),
}
}
fn calibrate(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
let xtal_freq = RtcClock::get_xtal_freq();
let xtal_cycles = RtcClock::calibrate_internal(cal_clk, slowclk_cycles) as u64;
let divider = xtal_freq.mhz() as u64 * slowclk_cycles as u64;
let period_64 = ((xtal_cycles << RtcClock::CAL_FRACT) + divider / 2u64 - 1u64) / divider;
(period_64 & u32::MAX as u64) as u32
}
/// Calibration of RTC_SLOW_CLK is performed using a special feature of
/// TIMG0. This feature counts the number of XTAL clock cycles within a
/// given number of RTC_SLOW_CLK cycles.
fn calibrate_internal(mut cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
const SOC_CLK_RC_FAST_FREQ_APPROX: u32 = 17_500_000;
const SOC_CLK_RC_SLOW_FREQ_APPROX: u32 = 136_000;
const SOC_CLK_XTAL32K_FREQ_APPROX: u32 = 32768;
if cal_clk == RtcCalSel::RtcCalRtcMux {
cal_clk = match cal_clk {
RtcCalSel::RtcCalRtcMux => match RtcClock::get_slow_freq() {
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
_ => cal_clk,
},
RtcCalSel::RtcCal32kOscSlow => RtcCalSel::RtcCalRtcMux,
_ => cal_clk,
};
}
let lp_clkrst = unsafe { &*LP_CLKRST::ptr() };
let pcr = unsafe { &*PCR::ptr() };
let pmu = unsafe { &*PMU::ptr() };
let clk_src = RtcClock::get_slow_freq();
if cal_clk == RtcCalSel::RtcCalRtcMux {
cal_clk = match clk_src {
RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRcSlow,
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCal32kOscSlow,
};
}
let cali_clk_sel;
if cal_clk == RtcCalSel::RtcCalRtcMux {
cal_clk = match clk_src {
RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRcSlow,
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCalRcSlow,
}
}
if cal_clk == RtcCalSel::RtcCalRcFast {
cali_clk_sel = RtcCaliClkSel::CaliClkRcFast;
} else if cal_clk == RtcCalSel::RtcCalRcSlow {
cali_clk_sel = RtcCaliClkSel::CaliClkRcSlow;
} else {
cali_clk_sel = RtcCaliClkSel::CaliClk32k;
match cal_clk {
RtcCalSel::RtcCalRtcMux | RtcCalSel::RtcCalRcSlow | RtcCalSel::RtcCalRcFast => (),
RtcCalSel::RtcCal32kRc => pcr
.ctrl_32k_conf
.modify(|_, w| unsafe { w.clk_32k_sel().bits(0) }),
RtcCalSel::RtcCal32kXtal => pcr
.ctrl_32k_conf
.modify(|_, w| unsafe { w.clk_32k_sel().bits(1) }),
RtcCalSel::RtcCal32kOscSlow => pcr
.ctrl_32k_conf
.modify(|_, w| unsafe { w.clk_32k_sel().bits(2) }),
}
}
// Enable requested clock (150k is always on)
// Some delay is required before the time is stable
// Only enable if originaly was disabled
// If clock is already on, do nothing
let dig_32k_xtal_enabled = lp_clkrst.clk_to_hp.read().icg_hp_xtal32k().bit_is_set();
if cal_clk == RtcCalSel::RtcCal32kXtal && !dig_32k_xtal_enabled {
lp_clkrst
.clk_to_hp
.modify(|_, w| w.icg_hp_xtal32k().set_bit());
}
// TODO: very hacky
// in ESP-IDF these are not called in this function but the fields are set
lp_clkrst
.clk_to_hp
.modify(|_, w| w.icg_hp_xtal32k().set_bit());
pmu.hp_sleep_lp_ck_power
.modify(|_, w| w.hp_sleep_xpd_xtal32k().set_bit());
pmu.hp_sleep_lp_ck_power
.modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
let rc_fast_enabled = pmu
.hp_sleep_lp_ck_power
.read()
.hp_sleep_xpd_fosc_clk()
.bit_is_set();
let dig_rc_fast_enabled = lp_clkrst.clk_to_hp.read().icg_hp_fosc().bit_is_set();
if cal_clk == RtcCalSel::RtcCalRcFast {
if !rc_fast_enabled {
pmu.hp_sleep_lp_ck_power
.modify(|_, w| w.hp_sleep_xpd_fosc_clk().set_bit());
unsafe {
ets_delay_us(50);
}
}
if !dig_rc_fast_enabled {
lp_clkrst.clk_to_hp.modify(|_, w| w.icg_hp_fosc().set_bit());
unsafe {
ets_delay_us(5);
}
}
}
let rc32k_enabled = pmu
.hp_sleep_lp_ck_power
.read()
.hp_sleep_xpd_rc32k()
.bit_is_set();
let dig_rc32k_enabled = lp_clkrst.clk_to_hp.read().icg_hp_osc32k().bit_is_set();
if cal_clk == RtcCalSel::RtcCal32kRc {
if !rc32k_enabled {
pmu.hp_sleep_lp_ck_power
.modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
unsafe {
ets_delay_us(300);
}
}
if !dig_rc32k_enabled {
lp_clkrst
.clk_to_hp
.modify(|_, w| w.icg_hp_osc32k().set_bit());
}
}
// Check if there is already running calibration process
// TODO: &mut TIMG0 for calibration
let timg0 = unsafe { &*TIMG0::ptr() };
if timg0
.rtccalicfg
.read()
.rtc_cali_start_cycling()
.bit_is_set()
{
timg0
.rtccalicfg2
.modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(1) });
// Set small timeout threshold to accelerate the generation of timeot
// Internal circuit will be reset when timeout occurs and will not affect the
// next calibration
while !timg0.rtccalicfg.read().rtc_cali_rdy().bit_is_set()
&& !timg0.rtccalicfg2.read().rtc_cali_timeout().bit_is_set()
{}
}
// Prepare calibration
timg0
.rtccalicfg
.modify(|_, w| unsafe { w.rtc_cali_clk_sel().bits(cali_clk_sel.clone() as u8) });
timg0
.rtccalicfg
.modify(|_, w| w.rtc_cali_start_cycling().clear_bit());
timg0
.rtccalicfg
.modify(|_, w| unsafe { w.rtc_cali_max().bits(slowclk_cycles as u16) });
let expected_freq = match cali_clk_sel {
RtcCaliClkSel::CaliClk32k => {
timg0.rtccalicfg2.modify(|_, w| unsafe {
w.rtc_cali_timeout_thres().bits(slowclk_cycles << 12)
});
SOC_CLK_XTAL32K_FREQ_APPROX
}
RtcCaliClkSel::CaliClkRcFast => {
timg0
.rtccalicfg2
.modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(0x01FFFFFF) });
SOC_CLK_RC_FAST_FREQ_APPROX
}
_ => {
timg0.rtccalicfg2.modify(|_, w| unsafe {
w.rtc_cali_timeout_thres().bits(slowclk_cycles << 10)
});
SOC_CLK_RC_SLOW_FREQ_APPROX
}
};
let us_time_estimate = (HertzU32::MHz(slowclk_cycles) / expected_freq).to_Hz();
// Start calibration
timg0
.rtccalicfg
.modify(|_, w| w.rtc_cali_start().clear_bit());
timg0.rtccalicfg.modify(|_, w| w.rtc_cali_start().set_bit());
// Wait for calibration to finish up to another us_time_estimate
unsafe {
ets_delay_us(us_time_estimate);
}
let cal_val = loop {
if timg0.rtccalicfg.read().rtc_cali_rdy().bit_is_set() {
break timg0.rtccalicfg1.read().rtc_cali_value().bits();
}
if timg0.rtccalicfg2.read().rtc_cali_timeout().bit_is_set() {
// Timed out waiting for calibration
break 0;
}
};
timg0
.rtccalicfg
.modify(|_, w| w.rtc_cali_start().clear_bit());
if cal_clk == RtcCalSel::RtcCal32kXtal && !dig_32k_xtal_enabled {
lp_clkrst
.clk_to_hp
.modify(|_, w| w.icg_hp_xtal32k().clear_bit());
}
if cal_clk == RtcCalSel::RtcCalRcFast {
if rc_fast_enabled {
pmu.hp_sleep_lp_ck_power
.modify(|_, w| w.hp_sleep_xpd_fosc_clk().set_bit());
unsafe {
ets_delay_us(50);
}
}
if dig_rc_fast_enabled {
lp_clkrst.clk_to_hp.modify(|_, w| w.icg_hp_fosc().set_bit());
unsafe {
ets_delay_us(5);
}
}
}
if cal_clk == RtcCalSel::RtcCal32kRc {
if rc32k_enabled {
pmu.hp_sleep_lp_ck_power
.modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
unsafe {
ets_delay_us(300);
}
}
if dig_rc32k_enabled {
lp_clkrst
.clk_to_hp
.modify(|_, w| w.icg_hp_osc32k().set_bit());
}
}
cal_val
}
pub(crate) fn cycles_to_1ms() -> u16 {
let period_13q19 = RtcClock::calibrate(
match RtcClock::get_slow_freq() {
RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRtcMux,
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCal32kOscSlow,
// RtcSlowClock::RtcCalRcFast => RtcCalSel::RtcCalRcFast,
},
1024,
);
// 100_000_000 is used to get rid of `float` calculations
let period = (100_000_000 * period_13q19 as u64) / (1 << RtcClock::CAL_FRACT);
(100_000_000 * 1000 / period) as u16
}
}

View File

@ -0,0 +1,62 @@
//! Reading of eFuses
use crate::peripherals::EFUSE;
pub struct Efuse;
impl Efuse {
/// Reads chip's MAC address from the eFuse storage.
///
/// # Example
///
/// ```
/// let mac_address = Efuse::get_mac_address();
/// writeln!(
/// serial_tx,
/// "MAC: {:#X}:{:#X}:{:#X}:{:#X}:{:#X}:{:#X}",
/// mac_address[0],
/// mac_address[1],
/// mac_address[2],
/// mac_address[3],
/// mac_address[4],
/// mac_address[5]
/// );
/// ```
pub fn get_mac_address() -> [u8; 6] {
let efuse = unsafe { &*EFUSE::ptr() };
let mac_low: u32 = efuse.rd_mac_sys_0.read().mac_0().bits();
let mac_high: u32 = efuse.rd_mac_sys_1.read().mac_1().bits() as u32;
let mac_low_bytes = mac_low.to_be_bytes();
let mac_high_bytes = mac_high.to_be_bytes();
[
mac_high_bytes[2],
mac_high_bytes[3],
mac_low_bytes[0],
mac_low_bytes[1],
mac_low_bytes[2],
mac_low_bytes[3],
]
}
/// Get status of SPI boot encryption.
pub fn get_flash_encryption() -> bool {
let efuse = unsafe { &*EFUSE::ptr() };
(efuse
.rd_repeat_data1
.read()
.spi_boot_crypt_cnt()
.bits()
.count_ones()
% 2)
!= 0
}
/// Get the multiplier for the timeout value of the RWDT STAGE 0 register.
pub fn get_rwdt_multiplier() -> u8 {
let efuse = unsafe { &*EFUSE::ptr() };
efuse.rd_repeat_data1.read().wdt_delay_sel().bits()
}
}

View File

@ -0,0 +1,263 @@
use paste::paste;
use crate::{
gpio::{
AlternateFunction,
Bank0GpioRegisterAccess,
GpioPin,
InputOutputAnalogPinType,
InputOutputPinType,
Unknown,
},
peripherals::GPIO,
};
// https://github.com/espressif/esp-idf/blob/df9310a/components/soc/esp32h2/gpio_periph.c#L42
pub const NUM_PINS: usize = 27;
pub type OutputSignalType = u8;
pub const OUTPUT_SIGNAL_MAX: u8 = 128;
pub const INPUT_SIGNAL_MAX: u8 = 124;
pub const ONE_INPUT: u8 = 0x1e;
pub const ZERO_INPUT: u8 = 0x1f;
pub(crate) const GPIO_FUNCTION: AlternateFunction = AlternateFunction::Function1;
pub(crate) const fn get_io_mux_reg(gpio_num: u8) -> &'static crate::peripherals::io_mux::GPIO {
unsafe { &(&*crate::peripherals::IO_MUX::PTR).gpio[gpio_num as usize] }
}
pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 {
int_enable as u8 | ((nmi_enable as u8) << 1)
}
/// Peripheral input signals for the GPIO mux
#[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone)]
pub enum InputSignal {
EXT_ADC_START = 0,
U0RXD = 6,
U0CTS = 7,
U0DSR = 8,
U1RXD = 9,
U1CTS = 10,
U1DSR = 11,
I2S_MCLK = 12,
I2SO_BCK = 13,
I2SO_WS = 14,
I2SI_SD = 15,
I2SI_BCK = 16,
I2SI_WS = 17,
USB_JTAG_TDO_BRIDGE = 19,
CPU_GPIO0 = 28,
CPU_GPIO1 = 29,
CPU_GPIO2 = 30,
CPU_GPIO3 = 31,
CPU_GPIO4 = 32,
CPU_GPIO5 = 33,
CPU_GPIO6 = 34,
CPU_GPIO7 = 35,
I2CEXT0_SCL = 45,
I2CEXT0_SDA = 46,
PARL_RX_DATA0 = 47,
PARL_RX_DATA1 = 48,
PARL_RX_DATA2 = 49,
PARL_RX_DATA3 = 50,
PARL_RX_DATA4 = 51,
PARL_RX_DATA5 = 52,
PARL_RX_DATA6 = 53,
PARL_RX_DATA7 = 54,
I2CEXT1_SCL = 55,
I2CEXT1_SDA = 56,
FSPICLK = 63,
FSPIQ = 64,
FSPID = 65,
FSPIHD = 66,
FSPIWP = 67,
FSPICS0 = 68,
PARL_RX_CLK = 69,
PARL_TX_CLK = 70,
RMT_SIG0 = 71,
RMT_SIG1 = 72,
TWAI0_RX = 73,
PWM0_SYNC0 = 87,
PWM0_SYNC1 = 88,
PWM0_SYNC2 = 89,
PWM0_F0 = 90,
PWM0_F1 = 91,
PWM0_F2 = 92,
PWM0_CAP0 = 93,
PWM0_CAP1 = 94,
PWM0_CAP2 = 95,
SIG_FUNC_97 = 97,
SIG_FUNC_98 = 98,
SIG_FUNC_99 = 99,
SIG_FUNC_100 = 100,
PCNT_SIG_CH00 = 101,
PCNT_SIG_CH10 = 102,
PCNT_CTRL_CH00 = 103,
PCNT_CTRL_CH10 = 104,
PCNT_SIG_CH01 = 105,
PCNT_SIG_CH11 = 106,
PCNT_CTRL_CH01 = 107,
PCNT_CTRL_CH11 = 108,
PCNT_SIG_CH02 = 109,
PCNT_SIG_CH12 = 110,
PCNT_CTRL_CH02 = 111,
PCNT_CTRL_CH12 = 112,
PCNT_SIG_CH03 = 113,
PCNT_SIG_CH13 = 114,
PCNT_CTRL_CH03 = 115,
PCNT_CTRL_CH13 = 116,
SPIQ = 121,
SPID = 122,
SPIHD = 123,
SPIWP = 124,
}
/// Peripheral input signals for the GPIO mux
#[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone)]
pub enum OutputSignal {
LEDC_LS_SIG_OUT0 = 0,
LEDC_LS_SIG_OUT1 = 1,
LEDC_LS_SIG_OUT2 = 2,
LEDC_LS_SIG_OUT3 = 3,
LEDC_LS_SIG_OUT4 = 4,
LEDC_LS_SIG_OUT5 = 5,
U0TXD = 6,
U0RTS = 7,
U0DTR = 8,
U1TXD = 9,
U1RTS = 10,
U1DTR = 11,
I2S_MCLK = 12,
I2SO_BCK = 13,
I2SO_WS = 14,
I2SO_SD = 15,
I2SI_BCK = 16,
I2SI_WS = 17,
I2SO_SD1 = 18,
USB_JTAG_TRST = 19,
CPU_GPIO_OUT0 = 28,
CPU_GPIO_OUT1 = 29,
CPU_GPIO_OUT2 = 30,
CPU_GPIO_OUT3 = 31,
CPU_GPIO_OUT4 = 32,
CPU_GPIO_OUT5 = 33,
CPU_GPIO_OUT6 = 34,
CPU_GPIO_OUT7 = 35,
I2CEXT0_SCL = 45,
I2CEXT0_SDA = 46,
PARL_TX_DATA0 = 47,
PARL_TX_DATA1 = 48,
PARL_TX_DATA2 = 49,
PARL_TX_DATA3 = 50,
PARL_TX_DATA4 = 51,
PARL_TX_DATA5 = 52,
PARL_TX_DATA6 = 53,
PARL_TX_DATA7 = 54,
I2CEXT1_SCL = 55,
I2CEXT1_SDA = 56,
FSPICLK_OUT_MUX = 63,
FSPIQ = 64,
FSPID = 65,
FSPIHD = 66,
FSPIWP = 67,
FSPICS0 = 68,
PARL_RX_CLK = 69,
PARL_TX_CLK = 70,
RMT_SIG_OUT0 = 71,
RMT_SIG_OUT1 = 72,
TWAI0_TX = 73,
TWAI0_BUS_OFF_ON = 74,
TWAI0_CLKOUT = 75,
TWAI0_STANDBY = 76,
CTE_ANT7 = 78,
CTE_ANT8 = 79,
CTE_ANT9 = 80,
GPIO_SD0 = 83,
GPIO_SD1 = 84,
GPIO_SD2 = 85,
GPIO_SD3 = 86,
PWM0_OUT0A = 87,
PWM0_OUT0B = 88,
PWM0_OUT1A = 89,
PWM0_OUT1B = 90,
PWM0_OUT2A = 91,
PWM0_OUT2B = 92,
SIG_IN_FUNC97 = 97,
SIG_IN_FUNC98 = 98,
SIG_IN_FUNC99 = 99,
SIG_IN_FUNC100 = 100,
FSPICS1 = 101,
FSPICS2 = 102,
FSPICS3 = 103,
FSPICS4 = 104,
FSPICS5 = 105,
CTE_ANT10 = 106,
CTE_ANT11 = 107,
CTE_ANT12 = 108,
CTE_ANT13 = 109,
CTE_ANT14 = 110,
CTE_ANT15 = 111,
SPICLK_OUT_MUX = 114,
SPICS0 = 115,
SPICS1 = 116,
SPIQ = 121,
SPID = 122,
SPIHD = 123,
SPIWP = 124,
CLK_OUT_OUT1 = 125,
CLK_OUT_OUT2 = 126,
CLK_OUT_OUT3 = 127,
GPIO = 128,
}
// FIXME: add alternate function numbers/signals where necessary
crate::gpio::gpio! {
Single,
(0, 0, InputOutput)
(1, 0, InputOutputAnalog)
(2, 0, InputOutputAnalog)
(3, 0, InputOutputAnalog)
(4, 0, InputOutputAnalog)
(5, 0, InputOutputAnalog)
(6, 0, InputOutput)
(7, 0, InputOutput)
(8, 0, InputOutput)
(9, 0, InputOutput)
(10, 0, InputOutput)
(11, 0, InputOutput)
(12, 0, InputOutput)
(13, 0, InputOutput)
(14, 0, InputOutput)
(15, 0, InputOutput)
(16, 0, InputOutput)
(17, 0, InputOutput)
(18, 0, InputOutput)
(19, 0, InputOutput)
(20, 0, InputOutput)
(21, 0, InputOutput)
(22, 0, InputOutput)
(23, 0, InputOutput)
(24, 0, InputOutput)
(25, 0, InputOutput)
(26, 0, InputOutput)
(27, 0, InputOutput)
}
crate::gpio::analog! {
1
2
3
4
5
}
// TODO USB pins
// implement marker traits on USB pins
// impl<T> crate::otg_fs::UsbSel for Gpio??<T> {}
// impl<T> crate::otg_fs::UsbDp for Gpio27<T> {}
// impl<T> crate::otg_fs::UsbDm for Gpio26<T> {}

View File

@ -0,0 +1,8 @@
pub mod efuse;
pub mod gpio;
pub mod peripherals;
pub mod radio_clocks;
pub(crate) mod registers {
pub const INTERRUPT_MAP_BASE: u32 = 0x60010000;
}

View File

@ -0,0 +1,63 @@
use esp32h2 as pac;
// We need to export this for users to use
pub use pac::Interrupt;
// We need to export this in the hal for the drivers to use
pub(crate) use self::peripherals::*;
crate::peripherals! {
// AES => true,
APB_SARADC => true,
// ASSIST_DEBUG => true,
// DS => true,
// ECC => true,
EFUSE => true,
// GDMA => true,
GPIO => true,
// HMAC => true,
// HP_APM => true,
// HP_SYS => true,
// I2C0 => true,
// I2C1 => true,
// I2S0 => true,
INTERRUPT_CORE0 => true,
INTPRI => true,
IO_MUX => true,
// LEDC => true,
// LP_ANA => true,
// LP_AON => true,
// LP_APM => true,
LP_CLKRST => true,
// LP_PERI => true,
// LP_TIMER => true,
LP_WDT => true,
// MCPWM0 => true,
// MEM_MONITOR => true,
// MODEM_LPCON => true,
// MODEM_SYSCON => true,
// OTP_DEBUG => true,
// PARL_IO => true,
// PAU => true,
// PCNT => true,
PCR => true,
// PMU => true,
// RMT => true,
// RNG => true,
// RSA => true,
// SHA => true,
// SOC_ETM => true,
// SPI0 => true,
// SPI1 => true,
// SPI2 => true,
SYSTIMER => true,
// TEE => true,
TIMG0 => true,
TIMG1 => true,
// TRACE => true,
// TWAI0 => true,
UART0 => true,
UART1 => true,
// UHCI0 => true,
// USB_DEVICE => true,
RADIO => false,
}

View File

@ -0,0 +1 @@

View File

@ -4,6 +4,7 @@ pub use self::soc::*;
#[cfg_attr(esp32c2, path = "esp32c2/mod.rs")]
#[cfg_attr(esp32c3, path = "esp32c3/mod.rs")]
#[cfg_attr(esp32c6, path = "esp32c6/mod.rs")]
#[cfg_attr(esp32h2, path = "esp32h2/mod.rs")]
#[cfg_attr(esp32s2, path = "esp32s2/mod.rs")]
#[cfg_attr(esp32s3, path = "esp32s3/mod.rs")]
mod soc;

View File

@ -13,11 +13,11 @@ use crate::peripheral::PeripheralRef;
#[cfg(esp32)]
type SystemPeripheral = crate::peripherals::DPORT;
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
type SystemPeripheral = crate::peripherals::PCR;
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
type IntPri = crate::peripherals::INTPRI;
#[cfg(not(any(esp32, esp32c6)))]
#[cfg(not(any(esp32, esp32c6, esp32h2)))]
type SystemPeripheral = crate::peripherals::SYSTEM;
pub enum SoftwareInterrupt {
@ -33,11 +33,13 @@ pub enum Peripheral {
Spi2,
#[cfg(spi3)]
Spi3,
#[cfg(i2c0)]
I2cExt0,
#[cfg(i2c1)]
I2cExt1,
#[cfg(rmt)]
Rmt,
#[cfg(ledc)]
Ledc,
#[cfg(mcpwm0)]
Mcpwm0,
@ -69,25 +71,31 @@ pub enum Peripheral {
Timg1,
#[cfg(lp_wdt)]
Wdt,
#[cfg(sha)]
Sha,
#[cfg(usb_device)]
UsbDevice,
#[cfg(uart0)]
Uart0,
#[cfg(uart1)]
Uart1,
#[cfg(uart2)]
Uart2,
#[cfg(rsa)]
Rsa,
}
pub struct SoftwareInterruptControl {
_private: (),
}
impl SoftwareInterruptControl {
pub fn raise(&mut self, interrupt: SoftwareInterrupt) {
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
let system = unsafe { &*SystemPeripheral::PTR };
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let system = unsafe { &*IntPri::PTR };
match interrupt {
SoftwareInterrupt::SoftwareInterrupt0 => {
system
@ -111,11 +119,13 @@ impl SoftwareInterruptControl {
}
}
}
pub fn reset(&mut self, interrupt: SoftwareInterrupt) {
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
let system = unsafe { &*SystemPeripheral::PTR };
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
let system = unsafe { &*IntPri::PTR };
match interrupt {
SoftwareInterrupt::SoftwareInterrupt0 => {
system
@ -146,7 +156,7 @@ pub struct PeripheralClockControl {
_private: (),
}
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
impl PeripheralClockControl {
/// Enables and resets the given peripheral
pub fn enable(&mut self, peripheral: Peripheral) {
@ -344,7 +354,7 @@ impl PeripheralClockControl {
}
}
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
impl PeripheralClockControl {
/// Enables and resets the given peripheral
pub fn enable(&mut self, peripheral: Peripheral) {
@ -356,9 +366,19 @@ impl PeripheralClockControl {
system.spi2_conf.modify(|_, w| w.spi2_clk_en().set_bit());
system.spi2_conf.modify(|_, w| w.spi2_rst_en().clear_bit());
}
#[cfg(i2c0)]
Peripheral::I2cExt0 => {
system.i2c_conf.modify(|_, w| w.i2c_clk_en().set_bit());
system.i2c_conf.modify(|_, w| w.i2c_rst_en().clear_bit());
// TODO: align register names between C6 and H2 in the PACs
#[cfg(esp32c6)]
{
system.i2c_conf.modify(|_, w| w.i2c_clk_en().set_bit());
system.i2c_conf.modify(|_, w| w.i2c_rst_en().clear_bit());
}
#[cfg(esp32h2)]
{
system.i2c0_conf.modify(|_, w| w.i2c0_clk_en().set_bit());
system.i2c0_conf.modify(|_, w| w.i2c0_rst_en().clear_bit());
}
}
#[cfg(rmt)]
Peripheral::Rmt => {
@ -428,18 +448,20 @@ impl PeripheralClockControl {
system
.timergroup0_timer_clk_conf
.write(|w| w.tg0_timer_clk_en().set_bit());
let bits = if cfg!(esp32c6) { 1 } else { 2 };
system
.timergroup0_timer_clk_conf
.write(|w| unsafe { w.tg0_timer_clk_sel().bits(1) });
.write(|w| unsafe { w.tg0_timer_clk_sel().bits(bits) });
}
#[cfg(timg1)]
Peripheral::Timg1 => {
system
.timergroup1_timer_clk_conf
.write(|w| w.tg1_timer_clk_en().set_bit());
let bits = if cfg!(esp32c6) { 1 } else { 2 };
system
.timergroup1_timer_clk_conf
.write(|w| unsafe { w.tg1_timer_clk_sel().bits(1) });
.write(|w| unsafe { w.tg1_timer_clk_sel().bits(bits) });
}
#[cfg(lp_wdt)]
Peripheral::Wdt => {
@ -457,10 +479,12 @@ impl PeripheralClockControl {
.timergroup1_timer_clk_conf
.write(|w| unsafe { w.tg1_timer_clk_sel().bits(1) });
}
#[cfg(sha)]
Peripheral::Sha => {
system.sha_conf.modify(|_, w| w.sha_clk_en().set_bit());
system.sha_conf.modify(|_, w| w.sha_rst_en().clear_bit());
}
#[cfg(usb_device)]
Peripheral::UsbDevice => {
system
.usb_device_conf
@ -469,18 +493,21 @@ impl PeripheralClockControl {
.usb_device_conf
.modify(|_, w| w.usb_device_rst_en().clear_bit());
}
#[cfg(uart0)]
Peripheral::Uart0 => {
system.uart0_conf.modify(|_, w| w.uart0_clk_en().set_bit());
system
.uart0_conf
.modify(|_, w| w.uart0_rst_en().clear_bit());
}
#[cfg(uart1)]
Peripheral::Uart1 => {
system.uart1_conf.modify(|_, w| w.uart1_clk_en().set_bit());
system
.uart1_conf
.modify(|_, w| w.uart1_rst_en().clear_bit());
}
#[cfg(rsa)]
Peripheral::Rsa => {
system.rsa_conf.modify(|_, w| w.rsa_clk_en().set_bit());
system.rsa_conf.modify(|_, w| w.rsa_rst_en().clear_bit());

View File

@ -37,7 +37,7 @@ where
{
_timer_group: PeripheralRef<'d, T>,
pub timer0: Timer<Timer0<T>>,
#[cfg(not(any(esp32c2, esp32c3, esp32c6)))]
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
pub timer1: Timer<Timer1<T>>,
pub wdt: Wdt<T>,
}
@ -80,7 +80,7 @@ where
peripheral_clock_control,
);
#[cfg(not(any(esp32c2, esp32c3, esp32c6)))]
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
let timer1 = Timer::new(
Timer1 {
phantom: PhantomData::default(),
@ -94,7 +94,7 @@ where
Self {
_timer_group: timer_group,
timer0,
#[cfg(not(any(esp32c2, esp32c3, esp32c6)))]
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
timer1,
wdt,
}
@ -332,13 +332,13 @@ where
}
}
#[cfg(not(any(esp32c2, esp32c3, esp32c6)))]
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
pub struct Timer1<TG> {
phantom: PhantomData<TG>,
}
/// Timer peripheral instance
#[cfg(not(any(esp32c2, esp32c3, esp32c6)))]
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
impl<TG> Instance for Timer1<TG>
where
TG: TimerGroupInstance,

View File

@ -354,7 +354,7 @@ where
/// Configures the RX-FIFO threshold
pub fn set_rx_fifo_full_threshold(&mut self, threshold: u16) {
#[cfg(any(esp32, esp32c6))]
#[cfg(any(esp32, esp32c6, esp32h2))]
let threshold: u8 = threshold as u8;
self.uart
@ -599,7 +599,7 @@ where
.write(|w| unsafe { w.clkdiv().bits(divider).frag().bits(0) });
}
#[cfg(esp32c6)]
#[cfg(any(esp32c6, esp32h2))]
fn change_baud(&self, baudrate: u32, clocks: &Clocks) {
// we force the clock source to be APB and don't use the decimal part of the
// divider
@ -608,7 +608,7 @@ where
let clk_div = ((clk) + (max_div * baudrate) - 1) / (max_div * baudrate);
// UART clocks are configured via PCR
let pcr = unsafe { &*esp32c6::PCR::PTR };
let pcr = unsafe { &*crate::peripherals::PCR::PTR };
match self.uart.uart_number() {
0 => {
@ -676,7 +676,7 @@ where
.write(|w| unsafe { w.clkdiv().bits(divider).frag().bits(0) });
}
#[cfg(esp32c6)] // TODO introduce a cfg symbol for this
#[cfg(any(esp32c6, esp32h2))] // TODO introduce a cfg symbol for this
#[inline(always)]
fn sync_regs(&mut self) {
self.uart
@ -696,7 +696,7 @@ where
}
}
#[cfg(not(esp32c6))]
#[cfg(not(any(esp32c6, esp32h2)))]
#[inline(always)]
fn sync_regs(&mut self) {}

View File

@ -34,5 +34,6 @@ esp32 = []
esp32c2 = []
esp32c3 = []
esp32c6 = []
esp32h2 = []
esp32s2 = []
esp32s3 = []

View File

@ -219,6 +219,8 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
let hal_crate = crate_name("esp32c3-hal");
#[cfg(feature = "esp32c6")]
let hal_crate = crate_name("esp32c6-hal");
#[cfg(feature = "esp32h2")]
let hal_crate = crate_name("esp32h2-hal");
#[cfg(feature = "esp32")]
let hal_crate_name = Ident::new("esp32_hal", Span::call_site().into());
@ -232,6 +234,8 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
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 = "esp32h2")]
let hal_crate_name = Ident::new("esp32h2_hal", Span::call_site().into());
let interrupt_in_hal_crate = match hal_crate {
Ok(FoundCrate::Itself) => {

View File

@ -18,6 +18,7 @@ smart-leds-trait = "0.2.1"
esp32 = ["esp-hal-common/esp32"]
esp32c3 = ["esp-hal-common/esp32c3"]
esp32c6 = ["esp-hal-common/esp32c6"]
esp32h2 = ["esp-hal-common/esp32h2"]
esp32s2 = ["esp-hal-common/esp32s2"]
esp32s3 = ["esp-hal-common/esp32s3"]

View File

@ -52,6 +52,8 @@ const SOURCE_CLK_FREQ: u32 = 40_000_000;
const SOURCE_CLK_FREQ: u32 = 40_000_000;
#[cfg(feature = "esp32c6")]
const SOURCE_CLK_FREQ: u32 = 40_000_000;
#[cfg(feature = "esp32h2")]
const SOURCE_CLK_FREQ: u32 = 40_000_000;
#[cfg(feature = "esp32s2")]
const SOURCE_CLK_FREQ: u32 = 40_000_000;
#[cfg(feature = "esp32s3")]

View File

@ -21,6 +21,9 @@
{
"path": "esp32c6-hal"
},
{
"path": "esp32h2-hal"
},
{
"path": "esp32s2-hal"
},

View File

@ -0,0 +1,11 @@
[target.riscv32imac-unknown-none-elf]
runner = "espflash flash --monitor"
rustflags = [
"-C", "link-arg=-Tlinkall.x",
]
[build]
target = "riscv32imac-unknown-none-elf"
[unstable]
build-std = [ "core" ]

60
esp32h2-hal/Cargo.toml Normal file
View File

@ -0,0 +1,60 @@
[package]
name = "esp32h2-hal"
version = "0.1.0"
authors = [
"Kirill Mikhailov <playfulfence@gmail.com>",
"Jesse Braham <jesse@beta7.io>",
]
edition = "2021"
rust-version = "1.60.0"
description = "HAL for ESP32-H2 microcontrollers"
repository = "https://github.com/esp-rs/esp-hal"
license = "MIT OR Apache-2.0"
keywords = [
"embedded",
"embedded-hal",
"esp",
"esp32h2",
"no-std",
]
categories = [
"embedded",
"hardware-support",
"no-std",
]
[dependencies]
cfg-if = "1.0.0"
embassy-time = { version = "0.1.1", features = ["nightly"], optional = true }
embedded-hal = { version = "0.2.7", features = ["unproven"] }
embedded-hal-1 = { version = "=1.0.0-alpha.10", optional = true, package = "embedded-hal" }
embedded-hal-async = { version = "0.2.0-alpha.1", optional = true }
embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true }
embedded-can = { version = "0.4.1", optional = true }
esp-hal-common = { version = "0.9.0", features = ["esp32h2"], path = "../esp-hal-common" }
[dev-dependencies]
aes = "0.8.2"
critical-section = "1.1.1"
embassy-executor = { version = "0.2.0", features = ["nightly", "integrated-timers"] }
embedded-graphics = "0.7.1"
esp-backtrace = { version = "0.7.0", features = ["esp32h2", "panic-handler", "exception-handler", "print-uart"] }
# esp-hal-smartled = { version = "0.1.0", features = ["esp32h2"], path = "../esp-hal-smartled" }
esp-println = { version = "0.5.0", features = ["esp32h2"] }
sha2 = { version = "0.10.6", default-features = false}
smart-leds = "0.3.0"
ssd1306 = "0.7.1"
static_cell = "1.0.0"
[features]
default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"]
direct-boot = ["esp-hal-common/rv-init-data", "esp-hal-common/rv-init-rtc-data"]
eh1 = ["esp-hal-common/eh1", "dep:embedded-hal-1", "dep:embedded-hal-nb", "dep:embedded-can"]
rt = []
ufmt = ["esp-hal-common/ufmt"]
vectored = ["esp-hal-common/vectored"]
async = ["esp-hal-common/async", "embedded-hal-async"]
embassy = ["esp-hal-common/embassy"]
embassy-time-systick = ["esp-hal-common/embassy-time-systick", "embassy-time/tick-hz-16_000_000"]
embassy-time-timg0 = ["esp-hal-common/embassy-time-timg0", "embassy-time/tick-hz-1_000_000"]

76
esp32h2-hal/README.md Normal file
View File

@ -0,0 +1,76 @@
# esp32h2-hal
<!-- [![Crates.io](https://img.shields.io/crates/v/esp32c6-hal?labelColor=1C2C2E&color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp32c6-hal)
[![docs.rs](https://img.shields.io/docsrs/esp32c6-hal?labelColor=1C2C2E&color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp32c6-hal)
![Crates.io](https://img.shields.io/crates/l/esp32c6-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-H2 from Espressif. Implements a number of the traits defined by [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. Refer to the [Getting Started](#getting-started) section below for more information.
<!-- ## [Documentation]
[documentation]: https://docs.rs/esp32c6-hal/
## Getting Started
### Installing the Rust Compiler Target
The compilation target for this device is officially supported via the `stable` release channel and can be installed via [rustup](https://rustup.rs/):
```shell
$ rustup target add riscv32imac-unknown-none-elf
```
### Supported boot methods
#### IDF Bootloader
The [IDF second stage bootloader](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-guides/startup.html#second-stage-bootloader) is the default bootloader solution.
By default, [espflash](https://github.com/esp-rs/espflash) fetches the required binaries (Bootloader and Partition Table) and flashes them onto the target device together with the Rust-based application firmware image.
#### Direct Boot
[Direct Boot](https://github.com/espressif/esp32c6-direct-boot-example#direct-boot-in-esp32-c6) allows an application stored in the External Flash to be executed directly, without being copied into Internal RAM.
##### Booting the Hello World example using Direct Boot
Build the Hello World example with support for Direct Boot:
```shell
cargo build --release --example hello_world --features direct-boot
```
Then proceed to generating the application binary and flashing it onto the target device:
```shell
cargo espflash --release --format direct-boot --features direct-boot --example hello_world --monitor
```
The ROM Bootloader will identify the firmware image built with Direct Boot support and load it appropriately from the External Flash:
```shell
ESP-ROM:esp32c6-20220919
Build:Sep 19 2022
rst:0x1 (POWERON),boot:0x6e (SPI_FAST_FLASH_BOOT)
Hello world!
Hello world!
Hello world!
```
-->
## 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.

74
esp32h2-hal/build.rs Normal file
View File

@ -0,0 +1,74 @@
use std::{env, fs::File, io::Write, path::PathBuf};
#[cfg(feature = "direct-boot")]
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("memory.x"))
.unwrap()
.write_all(include_bytes!("ld/db-esp32h2-memory.x"))
.unwrap();
File::create(out.join("esp32h2-link.x"))
.unwrap()
.write_all(include_bytes!("ld/db-esp32h2-link.x"))
.unwrap();
File::create(out.join("riscv-link.x"))
.unwrap()
.write_all(include_bytes!("ld/db-riscv-link.x"))
.unwrap();
File::create(out.join("linkall.x"))
.unwrap()
.write_all(include_bytes!("ld/db-linkall.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");
add_defaults();
}
#[cfg(not(feature = "direct-boot"))]
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("memory.x"))
.unwrap()
.write_all(include_bytes!("ld/bl-esp32h2-memory.x"))
.unwrap();
File::create(out.join("bl-riscv-link.x"))
.unwrap()
.write_all(include_bytes!("ld/bl-riscv-link.x"))
.unwrap();
File::create(out.join("linkall.x"))
.unwrap()
.write_all(include_bytes!("ld/bl-linkall.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");
add_defaults();
}
fn add_defaults() {
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("rom-functions.x"))
.unwrap()
.write_all(include_bytes!("ld/rom-functions.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());
}

View File

@ -0,0 +1,60 @@
//! Blinks an LED
//!
//! This assumes that a LED is connected to the pin assigned to `led`. (GPIO5)
#![no_std]
#![no_main]
use esp32h2_hal::{
clock::ClockControl,
gpio::IO,
peripherals::Peripherals,
prelude::*,
timer::TimerGroup,
Delay,
Rtc,
};
use esp_backtrace as _;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let mut system = peripherals.PCR.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
// Disable the watchdog timers. For the ESP32-H2, this includes the Super WDT,
// and the TIMG WDTs.
let mut rtc = Rtc::new(peripherals.LP_CLKRST);
let timer_group0 = TimerGroup::new(
peripherals.TIMG0,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt0 = timer_group0.wdt;
let timer_group1 = TimerGroup::new(
peripherals.TIMG1,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt1 = timer_group1.wdt;
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
wdt1.disable();
// Set GPIO5 as an output, and set its state high initially.
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let mut led = io.pins.gpio5.into_push_pull_output();
led.set_high().unwrap();
// Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop.
let mut delay = Delay::new(&clocks);
loop {
led.toggle().unwrap();
delay.delay_ms(500u32);
}
}

View File

@ -0,0 +1,55 @@
//! This shows how to write text to uart0.
//! You can see the output with `espflash` if you provide the `--monitor` option
#![no_std]
#![no_main]
use core::fmt::Write;
use esp32h2_hal::{
clock::ClockControl,
peripherals::Peripherals,
prelude::*,
timer::TimerGroup,
Rtc,
Uart,
};
use esp_backtrace as _;
use nb::block;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let mut system = peripherals.PCR.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
// Disable the watchdog timers. For the ESP32-H2, this includes the Super WDT,
// and the TIMG WDTs.
let mut rtc = Rtc::new(peripherals.LP_CLKRST);
let timer_group0 = TimerGroup::new(
peripherals.TIMG0,
&clocks,
&mut system.peripheral_clock_control,
);
let mut timer0 = timer_group0.timer0;
let mut wdt0 = timer_group0.wdt;
let timer_group1 = TimerGroup::new(
peripherals.TIMG1,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt1 = timer_group1.wdt;
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
wdt1.disable();
let mut uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control);
timer0.start(1u64.secs());
loop {
writeln!(uart0, "Hello world!").unwrap();
block!(timer0.wait()).unwrap();
}
}

View File

@ -0,0 +1,51 @@
//! Prints time in milliseconds from the RTC Timer
#![no_std]
#![no_main]
use esp32h2_hal::{
clock::ClockControl,
peripherals::Peripherals,
prelude::*,
timer::TimerGroup,
Delay,
Rtc,
};
use esp_backtrace as _;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let mut system = peripherals.PCR.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
// Disable the watchdog timers. For the ESP32-H2, this includes the Super WDT,
// and the TIMG WDTs.
let mut rtc = Rtc::new(peripherals.LP_CLKRST);
let timer_group0 = TimerGroup::new(
peripherals.TIMG0,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt0 = timer_group0.wdt;
let timer_group1 = TimerGroup::new(
peripherals.TIMG1,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt1 = timer_group1.wdt;
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
wdt1.disable();
// Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop.
let mut delay = Delay::new(&clocks);
loop {
esp_println::println!("rtc time in milliseconds is {}", rtc.get_time_ms());
delay.delay_ms(1000u32);
}
}

View File

@ -0,0 +1,86 @@
//! This demos the RTC Watchdog Timer (RWDT).
//! The RWDT is initially configured to trigger an interrupt after a given
//! timeout. Then, upon expiration, the RWDT is restarted and then reconfigured
//! to reset both the main system and the RTC.
#![no_std]
#![no_main]
use core::cell::RefCell;
use critical_section::Mutex;
use esp32h2_hal::{
clock::ClockControl,
interrupt,
peripherals::{self, Peripherals},
prelude::*,
riscv,
timer::TimerGroup,
Rtc,
Rwdt,
};
use esp_backtrace as _;
static RWDT: Mutex<RefCell<Option<Rwdt>>> = Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let mut system = peripherals.PCR.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timer_group0 = TimerGroup::new(
peripherals.TIMG0,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt0 = timer_group0.wdt;
let timer_group1 = TimerGroup::new(
peripherals.TIMG1,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt1 = timer_group1.wdt;
wdt0.disable();
wdt1.disable();
let mut rtc = Rtc::new(peripherals.LP_CLKRST);
// Disable watchdog timers
rtc.swd.disable();
rtc.rwdt.disable();
rtc.rwdt.start(2000u64.millis());
rtc.rwdt.listen();
interrupt::enable(
peripherals::Interrupt::LP_WDT,
interrupt::Priority::Priority1,
)
.unwrap();
critical_section::with(|cs| RWDT.borrow_ref_mut(cs).replace(rtc.rwdt));
unsafe {
riscv::interrupt::enable();
}
loop {}
}
#[interrupt]
fn LP_WDT() {
critical_section::with(|cs| {
esp_println::println!("RWDT Interrupt");
let mut rwdt = RWDT.borrow_ref_mut(cs);
let rwdt = rwdt.as_mut().unwrap();
rwdt.clear_interrupt();
esp_println::println!("Restarting in 5 seconds...");
rwdt.start(5000u64.millis());
rwdt.unlisten();
});
}

View File

@ -0,0 +1,53 @@
//! This demos the watchdog timer.
//! Basically the same as `hello_world` but if you remove the call to
//! `wdt.feed()` the watchdog will reset the system.
#![no_std]
#![no_main]
use esp32h2_hal::{
clock::ClockControl,
peripherals::Peripherals,
prelude::*,
timer::TimerGroup,
Rtc,
};
use esp_backtrace as _;
use esp_println::println;
use nb::block;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let mut system = peripherals.PCR.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let mut rtc = Rtc::new(peripherals.LP_CLKRST);
let timer_group0 = TimerGroup::new(
peripherals.TIMG0,
&clocks,
&mut system.peripheral_clock_control,
);
let mut timer0 = timer_group0.timer0;
let mut wdt0 = timer_group0.wdt;
let timer_group1 = TimerGroup::new(
peripherals.TIMG1,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt1 = timer_group1.wdt;
// Disable watchdog timers
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.start(2u64.secs());
wdt1.disable();
timer0.start(1u64.secs());
loop {
wdt0.feed();
println!("Hello world!");
block!(timer0.wait()).unwrap();
}
}

View File

@ -0,0 +1,38 @@
MEMORY
{
/* MEMORY_MAP = [
[0x00000000, 0x00010000, "PADDING"],
[0x42800000, 0x43000000, "DROM"],
[0x40800000, 0x40850000, "RAM"],
[0x40800000, 0x40850000, "BYTE_ACCESSIBLE"],
[0x4001С400, 0x40020000, "DROM_MASK"],
[0x40000000, 0x4001С400, "ROM_MASK"],
[0x42000000, 0x42800000, "ROM"],
[0x40800000, 0x40850000, "RAM"],
[0x50000000, 0x50001000, "RTC_RAM"],
[0x50000000, 0x50001000, "RTC_RAM"],
[0x600FE000, 0x60100000, "MEM_INTERNAL2"],
] */
/* 320K of on soc RAM, 16K reserved for cache */
ICACHE : ORIGIN = 0x40800000, LENGTH = 16K
/* Instruction and Data RAM */
RAM : ORIGIN = 0x40800000 + 16K, LENGTH = 320K - 16K
/* External flash */
/* Instruction and Data ROM */
ROM : ORIGIN = 0x42000000, LENGTH = 0x400000
/* RTC fast memory (executable). Persists over deep sleep. */
RTC_FAST : ORIGIN = 0x50000000, LENGTH = 16K /*- ESP_BOOTLOADER_RESERVE_RTC*/
}
REGION_ALIAS("ROTEXT", ROM);
REGION_ALIAS("RODATA", ROM);
REGION_ALIAS("RWTEXT", RAM);
REGION_ALIAS("RWDATA", RAM);
REGION_ALIAS("RTC_FAST_RWTEXT", RTC_FAST);
REGION_ALIAS("RTC_FAST_RWDATA", RTC_FAST);

View File

@ -0,0 +1,4 @@
INCLUDE "memory.x"
INCLUDE "bl-riscv-link.x"
INCLUDE "hal-defaults.x"
INCLUDE "rom-functions.x"

View File

@ -0,0 +1,83 @@
ENTRY(_start)
PROVIDE(_stext = ORIGIN(ROTEXT));
PROVIDE(_stack_start = ORIGIN(RWDATA) + LENGTH(RWDATA));
PROVIDE(_max_hart_id = 0);
PROVIDE(_hart_stack_size = 2K);
PROVIDE(_heap_size = 0);
PROVIDE(UserSoft = DefaultHandler);
PROVIDE(SupervisorSoft = DefaultHandler);
PROVIDE(MachineSoft = DefaultHandler);
PROVIDE(UserTimer = DefaultHandler);
PROVIDE(SupervisorTimer = DefaultHandler);
PROVIDE(MachineTimer = DefaultHandler);
PROVIDE(UserExternal = DefaultHandler);
PROVIDE(SupervisorExternal = DefaultHandler);
PROVIDE(MachineExternal = DefaultHandler);
PROVIDE(DefaultHandler = DefaultInterruptHandler);
PROVIDE(ExceptionHandler = DefaultExceptionHandler);
/* The ESP32-C2 and ESP32-C3 have interrupt IDs 1-31, while the ESP32-C6 and ESP32-H2 has
IDs 0-31, so we much define the handler for the one additional interrupt
ID: */
PROVIDE(interrupt0 = DefaultHandler);
PROVIDE(__post_init = default_post_init);
/* A PAC/HAL defined routine that should initialize custom interrupt controller if needed. */
PROVIDE(_setup_interrupts = default_setup_interrupts);
/* # Multi-processing hook function
fn _mp_hook() -> bool;
This function is called from all the harts and must return true only for one hart,
which will perform memory initialization. For other harts it must return false
and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt).
*/
PROVIDE(_mp_hook = default_mp_hook);
/* # Start trap function override
By default uses the riscv crates default trap handler
but by providing the `_start_trap` symbol external crates can override.
*/
PROVIDE(_start_trap = default_start_trap);
/* Must be called __global_pointer$ for linker relaxations to work. */
PROVIDE(__global_pointer$ = _data_start + 0x800);
SECTIONS {
/* These symbols/functions need to be near eachother, group them together at the start of text */
.text_init _stext : ALIGN(4)
{
KEEP(*(.init));
KEEP(*(.init.rust));
KEEP(*(.text.abort));
KEEP(*(.trap));
KEEP(*(.trap.rust));
} > ROTEXT
}
INSERT BEFORE .text;
SECTIONS {
/**
* Bootloader really wants to have separate segments for ROTEXT and RODATA
* Thus, we need to force a gap here.
*/
.text_gap (NOLOAD): {
. = . + 4;
. = ALIGN(4) + 0x20;
} > ROM
}
INSERT BEFORE .rodata;
/* Shared sections - ordering matters */
INCLUDE "text.x"
INCLUDE "rodata.x"
INCLUDE "rwdata.x"
INCLUDE "rwtext.x"
INCLUDE "rtc_fast.x"
/* End of Shared sections */
INCLUDE "debug.x"

View File

@ -0,0 +1,14 @@
INCLUDE memory.x
SECTIONS
{
.header : AT(0)
{
LONG(0xaedb041d)
LONG(0xaedb041d)
} > ROM
}
_stext = ORIGIN(ROM) + 8;
INCLUDE riscv-link.x

View File

@ -0,0 +1,39 @@
MEMORY
{
/* MEMORY_MAP = [
[0x00000000, 0x00010000, "PADDING"],
[0x42800000, 0x43000000, "DROM"],
[0x40800000, 0x40850000, "DRAM"],
[0x40800000, 0x40850000, "BYTE_ACCESSIBLE"],
[0x4001С400, 0x40020000, "DROM_MASK"],
[0x40000000, 0x4001С400, "IROM_MASK"],
[0x42000000, 0x42800000, "IROM"],
[0x40800000, 0x40850000, "IRAM"],
[0x50000000, 0x50001000, "RTC_IRAM"],
[0x50000000, 0x50001000, "RTC_DRAM"],
[0x600FE000, 0x60100000, "MEM_INTERNAL2"],
] */
/* 320K of on soc RAM, 16K reserved for cache */
ICACHE : ORIGIN = 0x40800000, LENGTH = 16K
RAM : ORIGIN = 0x40800000 + 32K, LENGTH = 320K - 16K
/* External flash */
ROM : ORIGIN = 0x42000000, LENGTH = 0x400000
/* RTC fast memory (executable). Persists over deep sleep. */
RTC_FAST : ORIGIN = 0x50000000, LENGTH = 16K /*- ESP_BOOTLOADER_RESERVE_RTC*/
}
REGION_ALIAS("REGION_TEXT", ROM);
REGION_ALIAS("REGION_RODATA", ROM);
REGION_ALIAS("REGION_DATA", RAM);
REGION_ALIAS("REGION_BSS", RAM);
REGION_ALIAS("REGION_HEAP", RAM);
REGION_ALIAS("REGION_STACK", RAM);
REGION_ALIAS("REGION_RWTEXT", RAM);
REGION_ALIAS("REGION_RTC_FAST", RTC_FAST);

View File

@ -0,0 +1,3 @@
INCLUDE "esp32h2-link.x"
INCLUDE "hal-defaults.x"
INCLUDE "rom-functions.x"

View File

@ -0,0 +1,237 @@
ENTRY(_start)
PROVIDE(_stext = ORIGIN(REGION_TEXT));
PROVIDE(_stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK));
PROVIDE(_max_hart_id = 0);
PROVIDE(_hart_stack_size = 2K);
PROVIDE(_heap_size = 0);
PROVIDE(UserSoft = DefaultHandler);
PROVIDE(SupervisorSoft = DefaultHandler);
PROVIDE(MachineSoft = DefaultHandler);
PROVIDE(UserTimer = DefaultHandler);
PROVIDE(SupervisorTimer = DefaultHandler);
PROVIDE(MachineTimer = DefaultHandler);
PROVIDE(UserExternal = DefaultHandler);
PROVIDE(SupervisorExternal = DefaultHandler);
PROVIDE(MachineExternal = DefaultHandler);
PROVIDE(DefaultHandler = DefaultInterruptHandler);
PROVIDE(ExceptionHandler = DefaultExceptionHandler);
/* The ESP32-C2 and ESP32-C3 have interrupt IDs 1-31, while the ESP32-C6 has
IDs 0-31, so we much define the handler for the one additional interrupt
ID: */
PROVIDE(interrupt0 = DefaultHandler);
PROVIDE(__post_init = default_post_init);
/* A PAC/HAL defined routine that should initialize custom interrupt controller if needed. */
PROVIDE(_setup_interrupts = default_setup_interrupts);
/* # Multi-processing hook function
fn _mp_hook() -> bool;
This function is called from all the harts and must return true only for one hart,
which will perform memory initialization. For other harts it must return false
and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt).
*/
PROVIDE(_mp_hook = default_mp_hook);
/* # Start trap function override
By default uses the riscv crates default trap handler
but by providing the `_start_trap` symbol external crates can override.
*/
PROVIDE(_start_trap = default_start_trap);
SECTIONS
{
.text.dummy (NOLOAD) :
{
/* This section is intended to make _stext address work */
. = ABSOLUTE(_stext);
} > REGION_TEXT
.text _stext :
{
/* Put reset handler first in .text section so it ends up as the entry */
/* point of the program. */
KEEP(*(.init));
KEEP(*(.init.rust));
KEEP(*(.text.abort));
. = ALIGN(4);
KEEP(*(.trap));
KEEP(*(.trap.rust));
*(.text .text.*);
_etext = .;
} > REGION_TEXT
_text_size = _etext - _stext + 8;
.rodata ORIGIN(ROM) + _text_size : AT(_text_size)
{
_srodata = .;
*(.srodata .srodata.*);
*(.rodata .rodata.*);
/* 4-byte align the end (VMA) of this section.
This is required by LLD to ensure the LMA of the following .data
section will have the correct alignment. */
. = ALIGN(4);
_erodata = .;
} > REGION_RODATA
_rodata_size = _erodata - _srodata + 8;
.data ORIGIN(RAM) : AT(_text_size + _rodata_size)
{
_data_start = .;
/* Must be called __global_pointer$ for linker relaxations to work. */
PROVIDE(__global_pointer$ = . + 0x800);
*(.sdata .sdata.* .sdata2 .sdata2.*);
*(.data .data.*);
. = ALIGN(4);
_data_end = .;
} > REGION_DATA
_data_size = _data_end - _data_start + 8;
.rwtext ORIGIN(REGION_RWTEXT) + _data_size : AT(_text_size + _rodata_size + _data_size){
_srwtext = .;
*(.rwtext);
. = ALIGN(4);
_erwtext = .;
} > REGION_RWTEXT
_rwtext_size = _erwtext - _srwtext + 8;
.rtc_fast.text : AT(_text_size + _rodata_size + _data_size + _rwtext_size) {
_srtc_fast_text = .;
*(.rtc_fast.literal .rtc_fast.text .rtc_fast.literal.* .rtc_fast.text.*)
. = ALIGN(4);
_ertc_fast_text = .;
} > REGION_RTC_FAST
_fast_text_size = _ertc_fast_text - _srtc_fast_text + 8;
.rtc_fast.data : AT(_text_size + _rodata_size + _data_size + _rwtext_size + _fast_text_size)
{
_rtc_fast_data_start = ABSOLUTE(.);
*(.rtc_fast.data .rtc_fast.data.*)
. = ALIGN(4);
_rtc_fast_data_end = ABSOLUTE(.);
} > REGION_RTC_FAST
_rtc_fast_data_size = _rtc_fast_data_end - _rtc_fast_data_start + 8;
.rtc_fast.bss (NOLOAD) : ALIGN(4)
{
_rtc_fast_bss_start = ABSOLUTE(.);
*(.rtc_fast.bss .rtc_fast.bss.*)
. = ALIGN(4);
_rtc_fast_bss_end = ABSOLUTE(.);
} > REGION_RTC_FAST
.rtc_fast.noinit (NOLOAD) : ALIGN(4)
{
*(.rtc_fast.noinit .rtc_fast.noinit.*)
} > REGION_RTC_FAST
.bss (NOLOAD) :
{
_bss_start = .;
*(.sbss .sbss.* .bss .bss.*);
. = ALIGN(4);
_bss_end = .;
} > REGION_BSS
/* ### .uninit */
.uninit (NOLOAD) : ALIGN(4)
{
. = ALIGN(4);
__suninit = .;
*(.uninit .uninit.*);
. = ALIGN(4);
__euninit = .;
} > REGION_BSS
/* fictitious region that represents the memory available for the heap */
.heap (NOLOAD) :
{
_sheap = .;
. += _heap_size;
. = ALIGN(4);
_eheap = .;
} > REGION_HEAP
/* fictitious region that represents the memory available for the stack */
.stack (NOLOAD) :
{
_estack = .;
. = ABSOLUTE(_stack_start);
_sstack = .;
} > REGION_STACK
/* fake output .got section */
/* Dynamic relocations are unsupported. This section is only used to detect
relocatable code in the input files and raise an error if relocatable code
is found */
.got (INFO) :
{
KEEP(*(.got .got.*));
}
.eh_frame (INFO) : { KEEP(*(.eh_frame)) }
.eh_frame_hdr (INFO) : { *(.eh_frame_hdr) }
}
PROVIDE(_sidata = _erodata + 8);
PROVIDE(_irwtext = ORIGIN(ROM) + _text_size + _rodata_size + _data_size);
PROVIDE(_irtc_fast_text = ORIGIN(ROM) + _text_size + _rodata_size + _data_size + _rwtext_size);
PROVIDE(_irtc_fast_data = ORIGIN(ROM) + _text_size + _rodata_size + _data_size + _rwtext_size + _fast_text_size);
/* Do not exceed this mark in the error messages above | */
ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
ASSERT(ORIGIN(REGION_RODATA) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_RODATA must be 4-byte aligned");
ASSERT(ORIGIN(REGION_DATA) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_DATA must be 4-byte aligned");
ASSERT(ORIGIN(REGION_HEAP) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_HEAP must be 4-byte aligned");
ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
ASSERT(ORIGIN(REGION_STACK) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_STACK must be 4-byte aligned");
ASSERT(_stext % 4 == 0, "
ERROR(riscv-rt): `_stext` must be 4-byte aligned");
ASSERT(_data_start % 4 == 0 && _data_end % 4 == 0, "
BUG(riscv-rt): .data is not 4-byte aligned");
ASSERT(_sidata % 4 == 0, "
BUG(riscv-rt): the LMA of .data is not 4-byte aligned");
ASSERT(_bss_start % 4 == 0 && _bss_end % 4 == 0, "
BUG(riscv-rt): .bss is not 4-byte aligned");
ASSERT(_sheap % 4 == 0, "
BUG(riscv-rt): start of .heap is not 4-byte aligned");
ASSERT(_stext + SIZEOF(.text) < ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT), "
ERROR(riscv-rt): The .text section must be placed inside the REGION_TEXT region.
Set _stext to an address smaller than 'ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT)'");
ASSERT(SIZEOF(.stack) > (_max_hart_id + 1) * _hart_stack_size, "
ERROR(riscv-rt): .stack section is too small for allocating stacks for all the harts.
Consider changing `_max_hart_id` or `_hart_stack_size`.");
ASSERT(SIZEOF(.got) == 0, "
.got section detected in the input files. Dynamic relocations are not
supported. If you are linking to C code compiled using the `gcc` crate
then modify your build script to compile the C code _without_ the
-fPIC flag. See the documentation of the `gcc::Config.fpic` method for
details.");
/* Do not exceed this mark in the error messages above | */

View File

@ -0,0 +1,14 @@
ets_printf = 0x40000028;
ets_update_cpu_frequency = ets_update_cpu_frequency_rom;
PROVIDE(esp_rom_printf = ets_printf);
PROVIDE(cache_invalidate_icache_all = 0x40000620);
PROVIDE(cache_suspend_icache = 0x4000066c);
PROVIDE(cache_resume_icache = 0x40000670);
/* TODO PROVIDE(cache_ibus_mmu_set = 0x40000560); */
/* TODO PROVIDE(cache_dbus_mmu_set = 0x40000564); */
PROVIDE(ets_delay_us = 0x40000040);
PROVIDE(ets_update_cpu_frequency_rom = 0x40000048);
PROVIDE(rtc_get_reset_reason = 0x40000018);
ets_update_cpu_frequency = 0x40000048;
PROVIDE(software_reset = 0x40000090);
PROVIDE(software_reset_cpu = 0x40000094);

14
esp32h2-hal/src/lib.rs Normal file
View File

@ -0,0 +1,14 @@
#![no_std]
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
pub use embedded_hal as ehal;
#[cfg(feature = "embassy")]
pub use esp_hal_common::embassy;
pub use esp_hal_common::*;
pub use self::gpio::IO;
/// Common module for analog functions
pub mod analog {
pub use esp_hal_common::analog::{AvailableAnalog, SarAdcExt};
}