Merge pull request #513 from esp-rs/feature/esp32h2
Add initial support for the ESP32-H2
This commit is contained in:
commit
c5d8cc62b8
41
.github/workflows/ci.yml
vendored
41
.github/workflows/ci.yml
vendored
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||

|
||||
[](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.)
|
||||
|
||||
|
||||
@ -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"]
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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") {
|
||||
|
||||
64
esp-hal-common/devices/esp32h2.toml
Normal file
64
esp-hal-common/devices/esp32h2.toml
Normal 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",
|
||||
]
|
||||
@ -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),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
360
esp-hal-common/src/clock/clocks_ll/esp32h2.rs
Normal file
360
esp-hal-common/src/clock/clocks_ll/esp32h2.rs
Normal 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);
|
||||
}
|
||||
@ -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.
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
640
esp-hal-common/src/rtc_cntl/rtc/esp32h2.rs
Normal file
640
esp-hal-common/src/rtc_cntl/rtc/esp32h2.rs
Normal 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
|
||||
}
|
||||
}
|
||||
62
esp-hal-common/src/soc/esp32h2/efuse.rs
Normal file
62
esp-hal-common/src/soc/esp32h2/efuse.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
263
esp-hal-common/src/soc/esp32h2/gpio.rs
Normal file
263
esp-hal-common/src/soc/esp32h2/gpio.rs
Normal 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> {}
|
||||
8
esp-hal-common/src/soc/esp32h2/mod.rs
Normal file
8
esp-hal-common/src/soc/esp32h2/mod.rs
Normal 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;
|
||||
}
|
||||
63
esp-hal-common/src/soc/esp32h2/peripherals.rs
Normal file
63
esp-hal-common/src/soc/esp32h2/peripherals.rs
Normal 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,
|
||||
}
|
||||
1
esp-hal-common/src/soc/esp32h2/radio_clocks.rs
Normal file
1
esp-hal-common/src/soc/esp32h2/radio_clocks.rs
Normal file
@ -0,0 +1 @@
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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) {}
|
||||
|
||||
|
||||
@ -34,5 +34,6 @@ esp32 = []
|
||||
esp32c2 = []
|
||||
esp32c3 = []
|
||||
esp32c6 = []
|
||||
esp32h2 = []
|
||||
esp32s2 = []
|
||||
esp32s3 = []
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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"]
|
||||
|
||||
|
||||
@ -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")]
|
||||
|
||||
@ -21,6 +21,9 @@
|
||||
{
|
||||
"path": "esp32c6-hal"
|
||||
},
|
||||
{
|
||||
"path": "esp32h2-hal"
|
||||
},
|
||||
{
|
||||
"path": "esp32s2-hal"
|
||||
},
|
||||
|
||||
11
esp32h2-hal/.cargo/config.toml
Normal file
11
esp32h2-hal/.cargo/config.toml
Normal 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
60
esp32h2-hal/Cargo.toml
Normal 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
76
esp32h2-hal/README.md
Normal file
@ -0,0 +1,76 @@
|
||||
# esp32h2-hal
|
||||
|
||||
<!-- [](https://crates.io/crates/esp32c6-hal)
|
||||
[](https://docs.rs/esp32c6-hal)
|
||||

|
||||
[](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
74
esp32h2-hal/build.rs
Normal 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());
|
||||
}
|
||||
60
esp32h2-hal/examples/blinky.rs
Normal file
60
esp32h2-hal/examples/blinky.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
55
esp32h2-hal/examples/hello_world.rs
Normal file
55
esp32h2-hal/examples/hello_world.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
51
esp32h2-hal/examples/rtc_time.rs
Normal file
51
esp32h2-hal/examples/rtc_time.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
86
esp32h2-hal/examples/rtc_watchdog.rs
Normal file
86
esp32h2-hal/examples/rtc_watchdog.rs
Normal 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();
|
||||
});
|
||||
}
|
||||
53
esp32h2-hal/examples/watchdog.rs
Normal file
53
esp32h2-hal/examples/watchdog.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
38
esp32h2-hal/ld/bl-esp32h2-memory.x
Normal file
38
esp32h2-hal/ld/bl-esp32h2-memory.x
Normal 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);
|
||||
4
esp32h2-hal/ld/bl-linkall.x
Normal file
4
esp32h2-hal/ld/bl-linkall.x
Normal file
@ -0,0 +1,4 @@
|
||||
INCLUDE "memory.x"
|
||||
INCLUDE "bl-riscv-link.x"
|
||||
INCLUDE "hal-defaults.x"
|
||||
INCLUDE "rom-functions.x"
|
||||
83
esp32h2-hal/ld/bl-riscv-link.x
Normal file
83
esp32h2-hal/ld/bl-riscv-link.x
Normal 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"
|
||||
14
esp32h2-hal/ld/db-esp32h2-link.x
Normal file
14
esp32h2-hal/ld/db-esp32h2-link.x
Normal 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
|
||||
39
esp32h2-hal/ld/db-esp32h2-memory.x
Normal file
39
esp32h2-hal/ld/db-esp32h2-memory.x
Normal 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);
|
||||
3
esp32h2-hal/ld/db-linkall.x
Normal file
3
esp32h2-hal/ld/db-linkall.x
Normal file
@ -0,0 +1,3 @@
|
||||
INCLUDE "esp32h2-link.x"
|
||||
INCLUDE "hal-defaults.x"
|
||||
INCLUDE "rom-functions.x"
|
||||
237
esp32h2-hal/ld/db-riscv-link.x
Normal file
237
esp32h2-hal/ld/db-riscv-link.x
Normal 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 | */
|
||||
14
esp32h2-hal/ld/rom-functions.x
Normal file
14
esp32h2-hal/ld/rom-functions.x
Normal 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
14
esp32h2-hal/src/lib.rs
Normal 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};
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user