diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 36faa940ff1..177048d990e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -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=esp3h2
# Check all Xtensa targets:
- name: check (esp32)
run: cd esp-hal-smartled/ && cargo +esp check --features=esp32,esp32_40mhz
@@ -180,6 +182,39 @@ jobs:
- name: check esp32c6-hal (async, spi)
run: cd esp32c6-hal/ && cargo +nightly-2023-03-09 check --example=embassy_spi --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
@@ -264,6 +299,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
@@ -305,6 +342,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
@@ -357,6 +396,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)
diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml
index e3217f2aaf4..992f5b56d9c 100644
--- a/esp-hal-common/Cargo.toml
+++ b/esp-hal-common/Cargo.toml
@@ -54,6 +54,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 = "0ee1cea", 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 }
@@ -66,6 +67,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"]
diff --git a/esp-hal-common/README.md b/esp-hal-common/README.md
index 63d364a08a7..dd61625c875 100644
--- a/esp-hal-common/README.md
+++ b/esp-hal-common/README.md
@@ -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)
diff --git a/esp-hal-common/build.rs b/esp-hal-common/build.rs
index 3c7dd7e95a2..d9438da95e7 100644
--- a/esp-hal-common/build.rs
+++ b/esp-hal-common/build.rs
@@ -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") {
diff --git a/esp-hal-common/devices/esp32h2.toml b/esp-hal-common/devices/esp32h2.toml
new file mode 100644
index 00000000000..37bb9dcd2db
--- /dev/null
+++ b/esp-hal-common/devices/esp32h2.toml
@@ -0,0 +1,65 @@
+[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",
+ # "peripherals",
+ # "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):
+ "plic",
+]
diff --git a/esp-hal-common/src/clock/clocks_ll/esp32h2.rs b/esp-hal-common/src/clock/clocks_ll/esp32h2.rs
new file mode 100644
index 00000000000..8cd6dabd07b
--- /dev/null
+++ b/esp-hal-common/src/clock/clocks_ll/esp32h2.rs
@@ -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);
+}
diff --git a/esp-hal-common/src/clock/mod.rs b/esp-hal-common/src/clock/mod.rs
index 2503dedcc3e..193dd5cea83 100644
--- a/esp-hal-common/src/clock/mod.rs
+++ b/esp-hal-common/src/clock/mod.rs
@@ -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))]
@@ -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
+ '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
+ '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.
diff --git a/esp-hal-common/src/lib.rs b/esp-hal-common/src/lib.rs
index b122c7fae0f..749170f04bc 100644
--- a/esp-hal-common/src/lib.rs
+++ b/esp-hal-common/src/lib.rs
@@ -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;
diff --git a/esp-hal-common/src/rtc_cntl/mod.rs b/esp-hal-common/src/rtc_cntl/mod.rs
index 485177adeb5..0c611a70698 100644
--- a/esp-hal-common/src/rtc_cntl/mod.rs
+++ b/esp-hal-common/src/rtc_cntl/mod.rs
@@ -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::{Clock, XtalClock};
#[cfg(not(esp32))]
use crate::efuse::Efuse;
-#[cfg(esp32c6)]
+#[cfg(any(esp32c6, esp32h2))]
use crate::peripherals::LP_WDT;
-#[cfg(not(esp32c6))]
+#[cfg(not(any(esp32c6, esp32h2)))]
use crate::peripherals::{RTC_CNTL, TIMG0};
use crate::{
peripheral::{Peripheral, PeripheralRef},
@@ -18,20 +18,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" {
@@ -42,7 +43,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
@@ -53,20 +54,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
@@ -79,7 +80,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 {
@@ -99,7 +100,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 {
@@ -117,7 +118,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,
}
@@ -129,23 +130,23 @@ 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()
}
}
-#[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;
@@ -162,7 +163,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 };
@@ -219,7 +220,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();
@@ -232,7 +233,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;
@@ -261,7 +262,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;
@@ -279,7 +280,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
@@ -454,7 +455,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,
@@ -467,7 +468,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;
@@ -524,9 +525,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;
@@ -549,9 +550,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;
@@ -574,9 +575,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);
@@ -590,9 +591,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! {
@@ -606,10 +607,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) });
@@ -618,9 +620,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);
@@ -641,9 +643,9 @@ impl WatchdogEnable for Rwdt {
where
T: Into,
{
- #[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;
@@ -655,13 +657,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()))
@@ -691,9 +693,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);
@@ -702,11 +704,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 {
@@ -715,14 +717,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
@@ -731,12 +733,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);
@@ -753,13 +755,11 @@ pub fn get_reset_reason(cpu: Cpu) -> Option {
}
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
@@ -767,7 +767,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
diff --git a/esp-hal-common/src/rtc_cntl/rtc/esp32h2.rs b/esp-hal-common/src/rtc_cntl/rtc/esp32h2.rs
new file mode 100644
index 00000000000..85eec95ea42
--- /dev/null
+++ b/esp-hal-common/src/rtc_cntl/rtc/esp32h2.rs
@@ -0,0 +1,95 @@
+use fugit::HertzU32;
+use strum::FromRepr;
+
+use crate::clock::Clock;
+
+pub(crate) fn init() {
+ todo!()
+}
+
+pub(crate) fn configure_clock() {
+ todo!()
+}
+
+// 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 {}
+
+impl Clock for RtcFastClock {
+ fn frequency(&self) -> HertzU32 {
+ todo!()
+ }
+}
+
+/// RTC SLOW_CLK frequency values
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub(crate) enum RtcSlowClock {}
+
+impl Clock for RtcSlowClock {
+ fn frequency(&self) -> HertzU32 {
+ todo!()
+ }
+}
+
+/// RTC Watchdog Timer
+pub struct RtcClock;
+
+/// RTC Watchdog Timer driver
+impl RtcClock {
+ /// Calculate the necessary RTC_SLOW_CLK cycles to complete 1 millisecond.
+ pub(crate) fn cycles_to_1ms() -> u16 {
+ todo!()
+ }
+}
diff --git a/esp-hal-common/src/soc/esp32h2/efuse.rs b/esp-hal-common/src/soc/esp32h2/efuse.rs
new file mode 100644
index 00000000000..2b53c682faa
--- /dev/null
+++ b/esp-hal-common/src/soc/esp32h2/efuse.rs
@@ -0,0 +1,34 @@
+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] {
+ todo!()
+ }
+
+ /// Get status of SPI boot encryption.
+ pub fn get_flash_encryption() -> bool {
+ todo!()
+ }
+
+ /// Get the multiplier for the timeout value of the RWDT STAGE 0 register.
+ pub fn get_rwdt_multiplier() -> u8 {
+ todo!()
+ }
+}
diff --git a/esp-hal-common/src/soc/esp32h2/gpio.rs b/esp-hal-common/src/soc/esp32h2/gpio.rs
new file mode 100644
index 00000000000..1328a17bd6e
--- /dev/null
+++ b/esp-hal-common/src/soc/esp32h2/gpio.rs
@@ -0,0 +1,30 @@
+use paste::paste;
+
+pub const NUM_PINS: usize = 0; // FIXME
+
+pub type OutputSignalType = u8;
+pub const OUTPUT_SIGNAL_MAX: u8 = 0; // FIXME
+pub const INPUT_SIGNAL_MAX: u8 = 0; // FIXME
+
+pub const ONE_INPUT: u8 = 0x1e;
+pub const ZERO_INPUT: u8 = 0x1f;
+
+/// Peripheral input signals for the GPIO mux
+#[allow(non_camel_case_types)]
+#[derive(PartialEq, Copy, Clone)]
+pub enum InputSignal {}
+
+/// Peripheral input signals for the GPIO mux
+#[allow(non_camel_case_types)]
+#[derive(PartialEq, Copy, Clone)]
+pub enum OutputSignal {}
+
+// crate::gpio::gpio! {}
+
+// crate::gpio::analog! {}
+
+// TODO USB pins
+// implement marker traits on USB pins
+// impl crate::otg_fs::UsbSel for Gpio?? {}
+// impl crate::otg_fs::UsbDp for Gpio12 {}
+// impl crate::otg_fs::UsbDm for Gpio13 {}
diff --git a/esp-hal-common/src/soc/esp32h2/mod.rs b/esp-hal-common/src/soc/esp32h2/mod.rs
new file mode 100644
index 00000000000..310b8d7141c
--- /dev/null
+++ b/esp-hal-common/src/soc/esp32h2/mod.rs
@@ -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;
+}
diff --git a/esp-hal-common/src/soc/esp32h2/peripherals.rs b/esp-hal-common/src/soc/esp32h2/peripherals.rs
new file mode 100644
index 00000000000..ca30eceb480
--- /dev/null
+++ b/esp-hal-common/src/soc/esp32h2/peripherals.rs
@@ -0,0 +1,64 @@
+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,
+ // Peripherals => 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,
+}
diff --git a/esp-hal-common/src/soc/esp32h2/radio_clocks.rs b/esp-hal-common/src/soc/esp32h2/radio_clocks.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/esp-hal-common/src/soc/esp32h2/radio_clocks.rs
@@ -0,0 +1 @@
+
diff --git a/esp-hal-common/src/soc/mod.rs b/esp-hal-common/src/soc/mod.rs
index 542c7f511c9..03e8e6ca7e5 100644
--- a/esp-hal-common/src/soc/mod.rs
+++ b/esp-hal-common/src/soc/mod.rs
@@ -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;
diff --git a/esp-hal-common/src/system.rs b/esp-hal-common/src/system.rs
index c2c98b69c9f..644cf175634 100755
--- a/esp-hal-common/src/system.rs
+++ b/esp-hal-common/src/system.rs
@@ -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 {
@@ -79,15 +79,18 @@ pub enum Peripheral {
#[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 +114,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 +151,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) {
@@ -490,6 +495,16 @@ impl PeripheralClockControl {
}
}
+#[cfg(esp32h2)]
+impl PeripheralClockControl {
+ /// Enables and resets the given peripheral
+ pub fn enable(&mut self, peripheral: Peripheral) {
+ let system = unsafe { &*SystemPeripheral::PTR };
+
+ todo!()
+ }
+}
+
/// Controls the configuration of the chip's clocks.
pub struct SystemClockControl {
_private: (),
diff --git a/esp-hal-procmacros/Cargo.toml b/esp-hal-procmacros/Cargo.toml
index a7a63697b0c..a5f91208270 100644
--- a/esp-hal-procmacros/Cargo.toml
+++ b/esp-hal-procmacros/Cargo.toml
@@ -34,5 +34,6 @@ esp32 = []
esp32c2 = []
esp32c3 = []
esp32c6 = []
+esp32h2 = []
esp32s2 = []
esp32s3 = []
diff --git a/esp-hal-procmacros/src/lib.rs b/esp-hal-procmacros/src/lib.rs
index 246e38bbc02..ab422c5ad44 100644
--- a/esp-hal-procmacros/src/lib.rs
+++ b/esp-hal-procmacros/src/lib.rs
@@ -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) => {
diff --git a/esp-hal-smartled/Cargo.toml b/esp-hal-smartled/Cargo.toml
index 1f1c9fb783b..38f8e854fa6 100644
--- a/esp-hal-smartled/Cargo.toml
+++ b/esp-hal-smartled/Cargo.toml
@@ -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"]
diff --git a/esp-hal-smartled/src/lib.rs b/esp-hal-smartled/src/lib.rs
index 171af7192fa..6e919f0e199 100644
--- a/esp-hal-smartled/src/lib.rs
+++ b/esp-hal-smartled/src/lib.rs
@@ -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")]
diff --git a/esp32h2-hal/.cargo/config.toml b/esp32h2-hal/.cargo/config.toml
new file mode 100644
index 00000000000..3e8a0bd0188
--- /dev/null
+++ b/esp32h2-hal/.cargo/config.toml
@@ -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" ]
diff --git a/esp32h2-hal/Cargo.toml b/esp32h2-hal/Cargo.toml
new file mode 100644
index 00000000000..b987b52570c
--- /dev/null
+++ b/esp32h2-hal/Cargo.toml
@@ -0,0 +1,60 @@
+[package]
+name = "esp32h2-hal"
+version = "0.1.0"
+authors = [
+ "Kirill Mikhailov "
+]
+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.0", features = ["nightly"], optional = true }
+embedded-hal = { version = "0.2.7", features = ["unproven"] }
+embedded-hal-1 = { version = "=1.0.0-alpha.9", optional = true, package = "embedded-hal" }
+embedded-hal-async = { version = "0.2.0-alpha.0", optional = true }
+embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true }
+embedded-can = { version = "0.4.1", optional = true }
+esp-hal-common = { version = "0.8.0", features = ["esp32h2"], path = "../esp-hal-common" }
+
+[dev-dependencies]
+aes = "0.8.2"
+critical-section = "1.1.1"
+embassy-executor = { package = "embassy-executor", git = "https://github.com/embassy-rs/embassy/", rev = "cd9a65b", 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.4.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"]
+
diff --git a/esp32h2-hal/README.md b/esp32h2-hal/README.md
new file mode 100644
index 00000000000..4ef79560392
--- /dev/null
+++ b/esp32h2-hal/README.md
@@ -0,0 +1,76 @@
+# esp32h2-hal
+
+
+
+`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.
+
+
+## License
+
+Licensed under either of:
+
+- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
+- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in
+the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without
+any additional terms or conditions.
diff --git a/esp32h2-hal/build.rs b/esp32h2-hal/build.rs
new file mode 100644
index 00000000000..b6161febd6d
--- /dev/null
+++ b/esp32h2-hal/build.rs
@@ -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());
+}
diff --git a/esp32h2-hal/examples/hello_world.rs b/esp32h2-hal/examples/hello_world.rs
new file mode 100644
index 00000000000..c19c07dfefa
--- /dev/null
+++ b/esp32h2-hal/examples/hello_world.rs
@@ -0,0 +1,21 @@
+#![no_std]
+#![no_main]
+
+use esp32h2_hal::{
+ clock::{ClockControl, CpuClock},
+ entry,
+ peripherals::Peripherals,
+ prelude::*,
+};
+use esp_backtrace as _;
+use esp_println::println;
+
+#[entry]
+fn main() -> ! {
+ let peripherals = Peripherals::take();
+ let system = peripherals.PCR.split();
+ let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock96MHz).freeze();
+
+ println!("Hello, world!");
+ loop {}
+}
diff --git a/esp32h2-hal/ld/bl-esp32h2-memory.x b/esp32h2-hal/ld/bl-esp32h2-memory.x
new file mode 100644
index 00000000000..c4a8be693af
--- /dev/null
+++ b/esp32h2-hal/ld/bl-esp32h2-memory.x
@@ -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);
diff --git a/esp32h2-hal/ld/bl-linkall.x b/esp32h2-hal/ld/bl-linkall.x
new file mode 100644
index 00000000000..e604dc6f8f8
--- /dev/null
+++ b/esp32h2-hal/ld/bl-linkall.x
@@ -0,0 +1,4 @@
+INCLUDE "memory.x"
+INCLUDE "bl-riscv-link.x"
+INCLUDE "hal-defaults.x"
+INCLUDE "rom-functions.x"
diff --git a/esp32h2-hal/ld/bl-riscv-link.x b/esp32h2-hal/ld/bl-riscv-link.x
new file mode 100644
index 00000000000..701a1684e32
--- /dev/null
+++ b/esp32h2-hal/ld/bl-riscv-link.x
@@ -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"
\ No newline at end of file
diff --git a/esp32h2-hal/ld/db-esp32h2-link.x b/esp32h2-hal/ld/db-esp32h2-link.x
new file mode 100644
index 00000000000..b2e740b39dc
--- /dev/null
+++ b/esp32h2-hal/ld/db-esp32h2-link.x
@@ -0,0 +1,14 @@
+INCLUDE memory.x
+
+SECTIONS
+{
+ .header : AT(0)
+ {
+ LONG(0xaedb041d)
+ LONG(0xaedb041d)
+ } > ROM
+}
+
+_stext = ORIGIN(ROM) + 8;
+
+INCLUDE riscv-link.x
diff --git a/esp32h2-hal/ld/db-esp32h2-memory.x b/esp32h2-hal/ld/db-esp32h2-memory.x
new file mode 100644
index 00000000000..869d65ee7f2
--- /dev/null
+++ b/esp32h2-hal/ld/db-esp32h2-memory.x
@@ -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);
diff --git a/esp32h2-hal/ld/db-linkall.x b/esp32h2-hal/ld/db-linkall.x
new file mode 100644
index 00000000000..e08ac551e0d
--- /dev/null
+++ b/esp32h2-hal/ld/db-linkall.x
@@ -0,0 +1,3 @@
+INCLUDE "esp32h2-link.x"
+INCLUDE "hal-defaults.x"
+INCLUDE "rom-functions.x"
diff --git a/esp32h2-hal/ld/db-riscv-link.x b/esp32h2-hal/ld/db-riscv-link.x
new file mode 100644
index 00000000000..a06c44e52b2
--- /dev/null
+++ b/esp32h2-hal/ld/db-riscv-link.x
@@ -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 | */
diff --git a/esp32h2-hal/ld/rom-functions.x b/esp32h2-hal/ld/rom-functions.x
new file mode 100644
index 00000000000..35ba4a68169
--- /dev/null
+++ b/esp32h2-hal/ld/rom-functions.x
@@ -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);
diff --git a/esp32h2-hal/src/lib.rs b/esp32h2-hal/src/lib.rs
new file mode 100644
index 00000000000..9c8f5599c2d
--- /dev/null
+++ b/esp32h2-hal/src/lib.rs
@@ -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};
+// }