diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36faa940ff1..177048d990e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,6 +44,8 @@ jobs: run: cd esp-hal-smartled/ && cargo +nightly-2023-03-09 check --features=esp32c3 - name: check (esp32c6) run: cd esp-hal-smartled/ && cargo +nightly-2023-03-09 check --features=esp32c6 + #- name: check (esp32h2) + # run: cd esp-hal-smartled/ && cargo +nightly-2023-03-09 check --features=esp3h2 # Check all Xtensa targets: - name: check (esp32) run: cd esp-hal-smartled/ && cargo +esp check --features=esp32,esp32_40mhz @@ -180,6 +182,39 @@ jobs: - name: check esp32c6-hal (async, spi) run: cd esp32c6-hal/ && cargo +nightly-2023-03-09 check --example=embassy_spi --features=embassy,embassy-time-systick,async + esp32h2-hal: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@v1 + with: + target: riscv32imac-unknown-none-elf + toolchain: nightly-2023-03-09 + components: rust-src + - uses: Swatinem/rust-cache@v2 + + # Perform a full build initially to verify that the examples not only + # build, but also link successfully. + # We also use this as an opportunity to verify that the examples link + # for each supported image format. + - name: build esp32h2-hal (no features) + run: cd esp32h2-hal/ && cargo +nightly-2023-03-09 build --examples + - name: build esp32h2-hal (direct-boot) + run: cd esp32h2-hal/ && cargo +nightly-2023-03-09 build --examples --features=direct-boot + # Subsequent steps can just check the examples instead, as we're already + # confident that they link. + - name: check esp32h2-hal (common features) + run: cd esp32h2-hal/ && cargo +nightly-2023-03-09 check --examples --features=eh1,ufmt + # - name: check esp32h2-hal (async, systick) + # run: cd esp32h2-hal/ && cargo +nightly-2023-03-09 check --example=embassy_hello_world --features=embassy,embassy-time-systick + # - name: check esp32h2-hal (async, timg0) + # run: cd esp32h2-hal/ && cargo +nightly-2023-03-09 check --example=embassy_hello_world --features=embassy,embassy-time-timg0 + # - name: check esp32h2-hal (async, gpio) + # run: cd esp32h2-hal/ && cargo +nightly-2023-03-09 check --example=embassy_wait --features=embassy,embassy-time-systick,async + # - name: check esp32h2-hal (async, spi) + # run: cd esp32h2-hal/ && cargo +nightly-2023-03-09 check --example=embassy_spi --features=embassy,embassy-time-systick,async + esp32s2-hal: runs-on: ubuntu-latest @@ -264,6 +299,8 @@ jobs: run: cd esp32c3-hal/ && cargo check --features=eh1,ufmt - name: msrv (esp32c6-hal) run: cd esp32c6-hal/ && cargo check --features=eh1,ufmt + - name: msrv (esp32h2-hal) + run: cd esp32h2-hal/ && cargo check --features=eh1,ufmt msrv-xtensa: runs-on: ubuntu-latest @@ -305,6 +342,8 @@ jobs: run: cargo +stable clippy --manifest-path=esp32c3-hal/Cargo.toml -- --no-deps - name: clippy (esp32c6-hal) run: cargo +stable clippy --manifest-path=esp32c6-hal/Cargo.toml -- --no-deps + - name: clippy (esp32h2-hal) + run: cargo +stable clippy --manifest-path=esp32h2-hal/Cargo.toml -- --no-deps clippy-xtensa: runs-on: ubuntu-latest @@ -357,6 +396,8 @@ jobs: run: cargo fmt --all --manifest-path=esp32c3-hal/Cargo.toml -- --check - name: rustfmt (esp32c6-hal) run: cargo fmt --all --manifest-path=esp32c6-hal/Cargo.toml -- --check + - name: rustfmt (esp32h2-hal) + run: cargo fmt --all --manifest-path=esp32h2-hal/Cargo.toml -- --check - name: rustfmt (esp32s2-hal) run: cargo fmt --all --manifest-path=esp32s2-hal/Cargo.toml -- --check - name: rustfmt (esp32s3-hal) diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index e3217f2aaf4..992f5b56d9c 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -54,6 +54,7 @@ esp32 = { version = "0.23.0", features = ["critical-section"], optional = true esp32c2 = { version = "0.11.0", features = ["critical-section"], optional = true } esp32c3 = { version = "0.14.0", features = ["critical-section"], optional = true } esp32c6 = { version = "0.4.0", features = ["critical-section"], optional = true } +esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "0ee1cea", package = "esp32h2", features = ["critical-section"], optional = true } esp32s2 = { version = "0.14.0", features = ["critical-section"], optional = true } esp32s3 = { version = "0.18.0", features = ["critical-section"], optional = true } @@ -66,6 +67,7 @@ esp32 = ["esp32/rt" , "xtensa", "xtensa-lx/esp32", "xtensa-lx-rt/esp32", esp32c2 = ["esp32c2/rt", "riscv", "procmacros/esp32c2"] esp32c3 = ["esp32c3/rt", "riscv", "procmacros/esp32c3"] esp32c6 = ["esp32c6/rt", "riscv", "procmacros/esp32c6"] +esp32h2 = ["esp32h2/rt", "riscv", "procmacros/esp32h2"] esp32s2 = ["esp32s2/rt", "xtensa", "xtensa-lx/esp32s2", "xtensa-lx-rt/esp32s2", "esp-synopsys-usb-otg", "usb-device", "procmacros/esp32s2"] esp32s3 = ["esp32s3/rt", "xtensa", "xtensa-lx/esp32s3", "xtensa-lx-rt/esp32s3", "lock_api", "esp-synopsys-usb-otg", "usb-device", "procmacros/esp32s3"] diff --git a/esp-hal-common/README.md b/esp-hal-common/README.md index 63d364a08a7..dd61625c875 100644 --- a/esp-hal-common/README.md +++ b/esp-hal-common/README.md @@ -13,6 +13,7 @@ This crate should not be used directly; you should use one of the device-specifi - [esp32c2-hal](../esp32c2-hal/README.md) - [esp32c3-hal](../esp32c3-hal/README.md) - [esp32c6-hal](../esp32c6-hal/README.md) +- [esp32h2-hal](../esp32h2-hal/README.md) - [esp32s2-hal](../esp32s2-hal/README.md) - [esp32s3-hal](../esp32s3-hal/README.md) diff --git a/esp-hal-common/build.rs b/esp-hal-common/build.rs index 3c7dd7e95a2..d9438da95e7 100644 --- a/esp-hal-common/build.rs +++ b/esp-hal-common/build.rs @@ -88,7 +88,9 @@ struct Config { fn main() { // NOTE: update when adding new device support! // Ensure that exactly one chip has been specified: - assert_unique_used_features!("esp32", "esp32c2", "esp32c3", "esp32c6", "esp32s2", "esp32s3"); + assert_unique_used_features!( + "esp32", "esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32s2", "esp32s3" + ); // Handle the features for the ESP32's different crystal frequencies: #[cfg(feature = "esp32")] @@ -112,6 +114,8 @@ fn main() { "esp32c3" } else if cfg!(feature = "esp32c6") { "esp32c6" + } else if cfg!(feature = "esp32h2") { + "esp32h2" } else if cfg!(feature = "esp32s2") { "esp32s2" } else if cfg!(feature = "esp32s3") { diff --git a/esp-hal-common/devices/esp32h2.toml b/esp-hal-common/devices/esp32h2.toml new file mode 100644 index 00000000000..37bb9dcd2db --- /dev/null +++ b/esp-hal-common/devices/esp32h2.toml @@ -0,0 +1,65 @@ +[device] +arch = "riscv" +cores = "single_core" + +peripherals = [ + # Peripherals available in the PAC: + # "aes", + # "apb_saradc", + # "assist_debug", + # "ds", + # "ecc", + "efuse", + # "gdma", + # "gpio", + # "hmac", + # "hp_apm", + # "hp_sys", + # "i2c0", + # "i2c1", + # "i2s0", + "interrupt_core0", + "intpri", + # "io_mux", + # "ledc", + # "lp_ana", + # "lp_aon", + # "lp_apm", + "lp_clkrst", + # "lp_peri", + # "lp_timer", + "lp_wdt", + # "mcpwm0", + # "mem_monitor", + # "modem_lpcon", + # "modem_syscon", + # "otp_debug", + # "parl_io", + # "pau", + # "pcnt", + "pcr", + # "pmu", + # "peripherals", + # "rmt", + # "rng", + # "rsa", + # "sha", + # "soc_etm", + # "spi0", + # "spi1", + # "spi2", + # "systimer", + # "tee", + # "timg0", + # "timg1", + # "trace", + # "twai0", + # "uart0", + # "uart1", + # "uhci0", + # "usb_device", + + + # Additional peripherals defined by us (the developers): + "plic", +] diff --git a/esp-hal-common/src/clock/clocks_ll/esp32h2.rs b/esp-hal-common/src/clock/clocks_ll/esp32h2.rs new file mode 100644 index 00000000000..8cd6dabd07b --- /dev/null +++ b/esp-hal-common/src/clock/clocks_ll/esp32h2.rs @@ -0,0 +1,360 @@ +use crate::clock::{ApbClock, Clock, CpuClock, PllClock, XtalClock}; + +extern "C" { + fn ets_update_cpu_frequency(ticks_per_us: u32); +} + +const I2C_BBPLL: u8 = 0x66; +const I2C_BBPLL_HOSTID: u8 = 0; +const I2C_BBPLL_OC_REF_DIV: u8 = 2; +const I2C_BBPLL_OC_REF_DIV_MSB: u8 = 3; +const I2C_BBPLL_OC_REF_DIV_LSB: u8 = 0; + +const I2C_BBPLL_OC_DIV: u8 = 3; +const I2C_BBPLL_OC_DIV_MSB: u8 = 5; +const I2C_BBPLL_OC_DIV_LSB: u8 = 0; + +const I2C_BBPLL_OC_DHREF_SEL: u8 = 5; +const I2C_BBPLL_OC_DHREF_SEL_MSB: u8 = 5; +const I2C_BBPLL_OC_DHREF_SEL_LSB: u8 = 4; + +const I2C_BBPLL_OC_DLREF_SEL: u8 = 5; +const I2C_BBPLL_OC_DLREF_SEL_MSB: u8 = 7; +const I2C_BBPLL_OC_DLREF_SEL_LSB: u8 = 6; + +const I2C_MST_ANA_CONF0_REG: u32 = 0x600AD800 + 0x18; +const I2C_MST_BBPLL_STOP_FORCE_HIGH: u32 = 1 << 2; +const I2C_MST_BBPLL_STOP_FORCE_LOW: u32 = 1 << 3; +const I2C_MST_BBPLL_CAL_DONE: u32 = 1 << 24; + +const MODEM_LPCON_CLK_CONF_FORCE_ON_REG: u32 = DR_REG_MODEM_LPCON_BASE + 0xc; +const MODEM_LPCON_CLK_I2C_MST_FO: u32 = 1 << 2; + +// May be needed for enabling I2C clock +const MODEM_LPCON_I2C_CLK_CONF_REG: u32 = DR_REG_MODEM_LPCON_BASE + 0x8; +const MODEM_LPCON_CLK_I2C_SEL_96M: u32 = 1 << 0; + +const DR_REG_MODEM_LPCON_BASE: u32 = 0x600AD000; +const MODEM_LPCON_CLK_CONF_REG: u32 = DR_REG_MODEM_LPCON_BASE + 0x8; +const MODEM_LPCON_CLK_I2C_MST_EN: u32 = 1 << 2; + +const DR_REG_I2C_ANA_MST_BASE: u32 = 0x600AD800; +const I2C_MST_DATE_REG: u32 = DR_REG_I2C_ANA_MST_BASE + 0x34; +const I2C_MST_ANA_CONF2_REG: u32 = DR_REG_I2C_ANA_MST_BASE + 0x20; +const I2C_MST_ANA_CONF2: u32 = 0x00FFFFFF; +const I2C_MST_CLK_EN: u32 = 1 << 28; + +const REGI2C_BBPLL: u8 = 0x66; +const REGI2C_BIAS: u8 = 0x6a; +const REGI2C_PMU_REG: u8 = 0x6d; +const REGI2C_ULP_CAL: u8 = 0x61; +const REGI2C_SAR_I2C: u8 = 0x69; + +const REGI2C_BBPLL_DEVICE_EN: u32 = 1 << 9; // (1 << 5) << 4; +const REGI2C_BIAS_DEVICE_EN: u32 = 1 << 8; // (1 << 4) << 4; +const REGI2C_PMU_DEVICE_EN: u32 = 1 << 12; // (1 << 8) << 4; +const REGI2C_ULP_CAL_DEVICE_EN: u32 = 1 << 10; // (1 << 6) << 4; +const REGI2C_SAR_I2C_DEVICE_EN: u32 = 1 << 11; // (1 << 7) << 4; + +const REGI2C_RTC_SLAVE_ID_V: u8 = 0xFF; +const REGI2C_RTC_SLAVE_ID_S: u8 = 0; +const REGI2C_RTC_ADDR_V: u8 = 0xFF; +const REGI2C_RTC_ADDR_S: u8 = 8; +const REGI2C_RTC_WR_CNTL_V: u8 = 0x1; +const REGI2C_RTC_WR_CNTL_S: u8 = 24; +const REGI2C_RTC_DATA_V: u8 = 0xFF; +const REGI2C_RTC_DATA_S: u8 = 16; + +const I2C_MST_I2C0_CTRL_REG: u32 = DR_REG_I2C_ANA_MST_BASE + 0x0; +const REGI2C_RTC_BUSY: u32 = 1 << 25; + +pub(crate) fn esp32h2_rtc_bbpll_configure(_xtal_freq: XtalClock, _pll_freq: PllClock) { + unsafe { + // Enable I2C master clock + (MODEM_LPCON_CLK_CONF_FORCE_ON_REG as *mut u32).write_volatile( + (MODEM_LPCON_CLK_CONF_FORCE_ON_REG as *mut u32).read_volatile() + | MODEM_LPCON_CLK_I2C_MST_FO, + ); + + // Set I2C clock to 96MHz + (MODEM_LPCON_I2C_CLK_CONF_REG as *mut u32).write_volatile( + (MODEM_LPCON_I2C_CLK_CONF_REG as *mut u32).read_volatile() + | MODEM_LPCON_CLK_I2C_SEL_96M, + ); + + let i2c_mst_ana_conf0_reg_ptr = I2C_MST_ANA_CONF0_REG as *mut u32; + + // BPPLL calibration start + i2c_mst_ana_conf0_reg_ptr.write_volatile( + i2c_mst_ana_conf0_reg_ptr.read_volatile() & !I2C_MST_BBPLL_STOP_FORCE_HIGH, + ); + i2c_mst_ana_conf0_reg_ptr.write_volatile( + i2c_mst_ana_conf0_reg_ptr.read_volatile() | I2C_MST_BBPLL_STOP_FORCE_LOW, + ); + + let oc_ref_div = 0u32; + let oc_div = 1u32; + let oc_dhref_sel = 3u32; + let oc_dlref_sel = 1u32; + + regi2c_write_mask( + I2C_BBPLL, + I2C_BBPLL_HOSTID, + I2C_BBPLL_OC_REF_DIV, + I2C_BBPLL_OC_REF_DIV_MSB, + I2C_BBPLL_OC_REF_DIV_LSB, + oc_ref_div as u8, + ); + + regi2c_write_mask( + I2C_BBPLL, + I2C_BBPLL_HOSTID, + I2C_BBPLL_OC_DIV, + I2C_BBPLL_OC_DIV_MSB, + I2C_BBPLL_OC_DIV_LSB, + oc_div as u8, + ); + + regi2c_write_mask( + I2C_BBPLL, + I2C_BBPLL_HOSTID, + I2C_BBPLL_OC_DHREF_SEL, + I2C_BBPLL_OC_DHREF_SEL_MSB, + I2C_BBPLL_OC_DHREF_SEL_LSB, + oc_dhref_sel as u8, + ); + + regi2c_write_mask( + I2C_BBPLL, + I2C_BBPLL_HOSTID, + I2C_BBPLL_OC_DLREF_SEL, + I2C_BBPLL_OC_DLREF_SEL_MSB, + I2C_BBPLL_OC_DLREF_SEL_LSB, + oc_dlref_sel as u8, + ); + + // WAIT CALIBRATION DONE + while (i2c_mst_ana_conf0_reg_ptr.read_volatile() & I2C_MST_BBPLL_CAL_DONE) == 0 {} + + // BBPLL CALIBRATION STOP + i2c_mst_ana_conf0_reg_ptr.write_volatile( + i2c_mst_ana_conf0_reg_ptr.read_volatile() | I2C_MST_BBPLL_STOP_FORCE_HIGH, + ); + i2c_mst_ana_conf0_reg_ptr.write_volatile( + i2c_mst_ana_conf0_reg_ptr.read_volatile() & !I2C_MST_BBPLL_STOP_FORCE_LOW, + ); + } +} + +pub(crate) fn esp32h2_rtc_bbpll_enable() { + let pmu = unsafe { &*crate::peripherals::PMU::PTR }; + + pmu.imm_hp_ck_power.modify(|_, w| { + w.tie_high_xpd_bb_i2c() + .set_bit() + .tie_high_xpd_bbpll() + .set_bit() + .tie_high_xpd_bbpll_i2c() + .set_bit() + }); + + pmu.imm_hp_ck_power + .modify(|_, w| w.tie_high_global_bbpll_icg().set_bit()); + + let pcr = unsafe { &*crate::peripherals::PCR::PTR }; + + // switch spimem to PLL 64Mhz clock + unsafe { + pcr.mspi_conf.modify(|_, w| w.mspi_clk_sel().bits(0b10)); + } +} + +pub(crate) fn esp32h2_rtc_update_to_xtal(freq: XtalClock, _div: u8) { + unsafe { + let pcr = &*crate::peripherals::PCR::PTR; + ets_update_cpu_frequency(freq.mhz()); + // Set divider from XTAL to APB clock. Need to set divider to 1 (reg. value 0) + // first. + pcr.ahb_freq_conf + .modify(|_, w| w.ahb_div_num().bits(_div - 1)); + + pcr.cpu_freq_conf + .modify(|_, w| w.cpu_div_num().bits(_div - 1)); + // Switch clock source + pcr.sysclk_conf.modify(|_, w| w.soc_clk_sel().bits(0)); + + clk_ll_bus_update(); + } +} + +pub(crate) fn esp32h2_rtc_freq_to_pll_mhz(cpu_clock_speed: CpuClock) { + let cpu_divider = 96 / cpu_clock_speed.mhz(); + clk_ll_cpu_set_divider(cpu_divider); + let ahb_divider = match cpu_divider { + 1 => 3, + 2 => 4, + _ => cpu_divider, + }; + clk_ll_ahb_set_divider(ahb_divider); + + let pcr = unsafe { &*crate::peripherals::PCR::PTR }; + + unsafe { + pcr.sysclk_conf.modify(|_, w| w.soc_clk_sel().bits(1)); + + clk_ll_bus_update(); + + ets_update_cpu_frequency(cpu_clock_speed.mhz()); + } +} + +pub(crate) fn esp32h2_rtc_apb_freq_update(apb_freq: ApbClock) { + let lp_aon = unsafe { &*crate::peripherals::LP_AON::ptr() }; + let value = ((apb_freq.hz() >> 12) & u16::MAX as u32) + | (((apb_freq.hz() >> 12) & u16::MAX as u32) << 16); + + lp_aon + .store5 + .modify(|_, w| unsafe { w.lp_aon_store5().bits(value) }); +} + +fn clk_ll_cpu_set_divider(divider: u32) { + assert!(divider >= 1); + + unsafe { + let pcr = &*crate::peripherals::PCR::PTR; + pcr.cpu_freq_conf + .modify(|_, w| w.cpu_div_num().bits((divider - 1) as u8)); + } +} + +fn clk_ll_ahb_set_divider(divider: u32) { + assert!(divider >= 1); + + unsafe { + let pcr = &*crate::peripherals::PCR::PTR; + pcr.ahb_freq_conf + .modify(|_, w| w.ahb_div_num().bits((divider - 1) as u8)); + } +} + +fn clk_ll_bus_update() { + unsafe { + let pcr = &*crate::peripherals::PCR::PTR; + + pcr.bus_clk_update + .modify(|_, w| w.bus_clock_update().bit(true)); + + // reg_get_bit + while pcr.bus_clk_update.read().bus_clock_update().bit_is_set() {} + } +} + +fn regi2c_enable_block(block: u8) { + reg_set_bit(MODEM_LPCON_CLK_CONF_REG, MODEM_LPCON_CLK_I2C_MST_EN); + reg_set_bit(I2C_MST_DATE_REG, I2C_MST_CLK_EN); + + // Make I2C_MST_ANA_CONF2 in I2C_MST_ANA_CONF2_REG be 0 + unsafe { + (I2C_MST_ANA_CONF2_REG as *mut u32).write_volatile( + // (1 << 18) + (I2C_MST_ANA_CONF2_REG as *mut u32).read_volatile() & !(I2C_MST_ANA_CONF2 as u32), + ); + } + + // Before config I2C register, enable corresponding slave. + match block { + REGI2C_BBPLL => { + reg_set_bit(I2C_MST_ANA_CONF2_REG, REGI2C_BBPLL_DEVICE_EN); + } + REGI2C_BIAS => { + reg_set_bit(I2C_MST_ANA_CONF2_REG, REGI2C_BIAS_DEVICE_EN); + } + REGI2C_PMU_REG => { + reg_set_bit(I2C_MST_ANA_CONF2_REG, REGI2C_PMU_DEVICE_EN); + } + REGI2C_ULP_CAL => { + reg_set_bit(I2C_MST_ANA_CONF2_REG, REGI2C_ULP_CAL_DEVICE_EN); + } + REGI2C_SAR_I2C => { + reg_set_bit(I2C_MST_ANA_CONF2_REG, REGI2C_SAR_I2C_DEVICE_EN); + } + _ => (), + } +} + +fn regi2c_disable_block(block: u8) { + match block { + REGI2C_BBPLL => { + reg_clr_bit(I2C_MST_ANA_CONF2_REG, REGI2C_BBPLL_DEVICE_EN); + } + REGI2C_BIAS => { + reg_clr_bit(I2C_MST_ANA_CONF2_REG, REGI2C_BIAS_DEVICE_EN); + } + REGI2C_PMU_REG => { + reg_clr_bit(I2C_MST_ANA_CONF2_REG, REGI2C_PMU_DEVICE_EN); + } + REGI2C_ULP_CAL => { + reg_clr_bit(I2C_MST_ANA_CONF2_REG, REGI2C_ULP_CAL_DEVICE_EN); + } + REGI2C_SAR_I2C => { + reg_clr_bit(I2C_MST_ANA_CONF2_REG, REGI2C_SAR_I2C_DEVICE_EN); + } + _ => (), + } +} + +fn reg_set_bit(reg: u32, bit: u32) { + unsafe { + (reg as *mut u32).write_volatile((reg as *mut u32).read_volatile() | bit); + } +} + +fn reg_clr_bit(reg: u32, bit: u32) { + unsafe { + (reg as *mut u32).write_volatile((reg as *mut u32).read_volatile() & !bit); + } +} + +fn reg_write(reg: u32, v: u32) { + unsafe { + (reg as *mut u32).write_volatile(v); + } +} + +fn reg_get_bit(reg: u32, b: u32) -> u32 { + unsafe { (reg as *mut u32).read_volatile() & b } +} + +fn reg_get_field(reg: u32, s: u32, v: u32) -> u32 { + unsafe { ((reg as *mut u32).read_volatile() >> s) & v } +} + +pub(crate) fn regi2c_write_mask(block: u8, _host_id: u8, reg_add: u8, msb: u8, lsb: u8, data: u8) { + assert!(msb - lsb < 8); + regi2c_enable_block(block); + + // Read the i2c bus register + let mut temp: u32 = ((block as u32 & REGI2C_RTC_SLAVE_ID_V as u32) + << REGI2C_RTC_SLAVE_ID_S as u32) + | (reg_add as u32 & REGI2C_RTC_ADDR_V as u32) << REGI2C_RTC_ADDR_S as u32; + reg_write(I2C_MST_I2C0_CTRL_REG, temp); + while reg_get_bit(I2C_MST_I2C0_CTRL_REG, REGI2C_RTC_BUSY) != 0 {} + temp = reg_get_field( + I2C_MST_I2C0_CTRL_REG, + REGI2C_RTC_DATA_S as u32, + REGI2C_RTC_DATA_V as u32, + ); + // Write the i2c bus register + temp &= (!(0xFFFFFFFF << lsb)) | (0xFFFFFFFF << (msb + 1)); + temp = + ((data as u32 & (!(0xFFFFFFFF << (msb as u32 - lsb as u32 + 1)))) << (lsb as u32)) | temp; + temp = ((block as u32 & REGI2C_RTC_SLAVE_ID_V as u32) << REGI2C_RTC_SLAVE_ID_S as u32) + | ((reg_add as u32 & REGI2C_RTC_ADDR_V as u32) << REGI2C_RTC_ADDR_S as u32) + | ((0x1 & REGI2C_RTC_WR_CNTL_V as u32) << REGI2C_RTC_WR_CNTL_S as u32) + | ((temp & REGI2C_RTC_DATA_V as u32) << REGI2C_RTC_DATA_S as u32); + reg_write(I2C_MST_I2C0_CTRL_REG, temp); + while reg_get_bit(I2C_MST_I2C0_CTRL_REG, REGI2C_RTC_BUSY) != 0 {} + + regi2c_disable_block(block); +} diff --git a/esp-hal-common/src/clock/mod.rs b/esp-hal-common/src/clock/mod.rs index 2503dedcc3e..193dd5cea83 100644 --- a/esp-hal-common/src/clock/mod.rs +++ b/esp-hal-common/src/clock/mod.rs @@ -10,6 +10,7 @@ use crate::{ #[cfg_attr(esp32c2, path = "clocks_ll/esp32c2.rs")] #[cfg_attr(esp32c3, path = "clocks_ll/esp32c3.rs")] #[cfg_attr(esp32c6, path = "clocks_ll/esp32c6.rs")] +#[cfg_attr(esp32h2, path = "clocks_ll/esp32h2.rs")] #[cfg_attr(esp32s2, path = "clocks_ll/esp32s2.rs")] #[cfg_attr(esp32s3, path = "clocks_ll/esp32s3.rs")] pub(crate) mod clocks_ll; @@ -30,6 +31,8 @@ pub trait Clock { #[derive(Debug, Clone, Copy)] pub enum CpuClock { Clock80MHz, + #[cfg(esp32h2)] + Clock96MHz, #[cfg(esp32c2)] Clock120MHz, #[cfg(not(esp32c2))] @@ -43,6 +46,8 @@ impl Clock for CpuClock { fn frequency(&self) -> HertzU32 { match self { CpuClock::Clock80MHz => HertzU32::MHz(80), + #[cfg(esp32h2)] + CpuClock::Clock96MHz => HertzU32::MHz(96), #[cfg(esp32c2)] CpuClock::Clock120MHz => HertzU32::MHz(120), #[cfg(not(esp32c2))] @@ -429,6 +434,58 @@ impl<'d> ClockControl<'d> { } } +#[cfg(esp32h2)] +impl<'d> ClockControl<'d> { + /// Use what is considered the default settings after boot. + #[allow(unused)] + pub fn boot_defaults( + clock_control: impl Peripheral

+ 'd, + ) -> ClockControl<'d> { + ClockControl { + _private: clock_control.into_ref(), + desired_rates: RawClocks { + cpu_clock: HertzU32::MHz(96), + apb_clock: HertzU32::MHz(32), + xtal_clock: HertzU32::MHz(32), + i2c_clock: HertzU32::MHz(32), + }, + } + } + + /// Configure the CPU clock speed. + #[allow(unused)] + pub fn configure( + clock_control: impl Peripheral

+ 'd, + cpu_clock_speed: CpuClock, + ) -> ClockControl<'d> { + let apb_freq; + let xtal_freq = XtalClock::RtcXtalFreqOther(32); + let pll_freq = PllClock::Pll320MHz; + + if cpu_clock_speed.mhz() <= xtal_freq.mhz() { + apb_freq = ApbClock::ApbFreqOther(cpu_clock_speed.mhz()); + clocks_ll::esp32h2_rtc_update_to_xtal(xtal_freq, 1); + clocks_ll::esp32h2_rtc_apb_freq_update(apb_freq); + } else { + apb_freq = ApbClock::ApbFreqOther(32); + clocks_ll::esp32h2_rtc_bbpll_enable(); + clocks_ll::esp32h2_rtc_bbpll_configure(xtal_freq, pll_freq); + clocks_ll::esp32h2_rtc_freq_to_pll_mhz(cpu_clock_speed); + clocks_ll::esp32h2_rtc_apb_freq_update(apb_freq); + } + + ClockControl { + _private: clock_control.into_ref(), + desired_rates: RawClocks { + cpu_clock: cpu_clock_speed.frequency(), + apb_clock: apb_freq.frequency(), + xtal_clock: xtal_freq.frequency(), + i2c_clock: HertzU32::MHz(32), + }, + } + } +} + #[cfg(esp32s2)] impl<'d> ClockControl<'d> { /// Use what is considered the default settings after boot. diff --git a/esp-hal-common/src/lib.rs b/esp-hal-common/src/lib.rs index b122c7fae0f..749170f04bc 100644 --- a/esp-hal-common/src/lib.rs +++ b/esp-hal-common/src/lib.rs @@ -9,6 +9,7 @@ //! - [esp32c2-hal] //! - [esp32c3-hal] //! - [esp32c6-hal] +//! - [esp32h2-hal] //! - [esp32s2-hal] //! - [esp32s3-hal] //! @@ -17,6 +18,7 @@ //! [esp32c2-hal]: https://github.com/esp-rs/esp-hal/tree/main/esp32c2-hal //! [esp32c3-hal]: https://github.com/esp-rs/esp-hal/tree/main/esp32c3-hal //! [esp32c6-hal]: https://github.com/esp-rs/esp-hal/tree/main/esp32c6-hal +//! [esp32h2-hal]: https://github.com/esp-rs/esp-hal/tree/main/esp32h2-hal //! [esp32s2-hal]: https://github.com/esp-rs/esp-hal/tree/main/esp32s2-hal //! [esp32s3-hal]: https://github.com/esp-rs/esp-hal/tree/main/esp32s3-hal @@ -42,6 +44,8 @@ pub use xtensa_lx_rt::{self, entry}; pub use self::analog::adc::implementation as adc; #[cfg(dac)] pub use self::analog::dac::implementation as dac; +#[cfg(any(xtensa, all(riscv, systimer)))] +pub use self::delay::Delay; #[cfg(gdma)] pub use self::dma::gdma; #[cfg(pdma)] @@ -58,6 +62,7 @@ pub use self::rtc_cntl::{Rtc, Rwdt}; pub use self::soc::cpu_control; #[cfg(efuse)] pub use self::soc::efuse; +pub use self::soc::peripherals; #[cfg(any(spi0, spi1, spi2, spi3))] pub use self::spi::Spi; #[cfg(any(timg0, timg1))] @@ -66,7 +71,6 @@ pub use self::timer::Timer; pub use self::uart::Uart; #[cfg(usb_device)] pub use self::usb_serial_jtag::UsbSerialJtag; -pub use self::{delay::Delay, soc::peripherals}; #[cfg(aes)] pub mod aes; @@ -75,6 +79,7 @@ pub mod analog; #[cfg(assist_debug)] pub mod assist_debug; pub mod clock; +#[cfg(any(xtensa, all(riscv, systimer)))] pub mod delay; #[cfg(any(gdma, pdma))] pub mod dma; diff --git a/esp-hal-common/src/rtc_cntl/mod.rs b/esp-hal-common/src/rtc_cntl/mod.rs index 485177adeb5..0c611a70698 100644 --- a/esp-hal-common/src/rtc_cntl/mod.rs +++ b/esp-hal-common/src/rtc_cntl/mod.rs @@ -1,16 +1,16 @@ use embedded_hal::watchdog::{Watchdog, WatchdogDisable, WatchdogEnable}; -#[cfg(not(esp32c6))] +#[cfg(not(any(esp32c6, esp32h2)))] use fugit::HertzU32; use fugit::MicrosDurationU64; pub use self::rtc::SocResetReason; -#[cfg(not(esp32c6))] +#[cfg(not(any(esp32c6, esp32h2)))] use crate::clock::{Clock, XtalClock}; #[cfg(not(esp32))] use crate::efuse::Efuse; -#[cfg(esp32c6)] +#[cfg(any(esp32c6, esp32h2))] use crate::peripherals::LP_WDT; -#[cfg(not(esp32c6))] +#[cfg(not(any(esp32c6, esp32h2)))] use crate::peripherals::{RTC_CNTL, TIMG0}; use crate::{ peripheral::{Peripheral, PeripheralRef}, @@ -18,20 +18,21 @@ use crate::{ Cpu, }; -#[cfg(esp32c6)] +#[cfg(any(esp32c6, esp32h2))] type RtcCntl = crate::peripherals::LP_CLKRST; -#[cfg(not(esp32c6))] +#[cfg(not(any(esp32c6, esp32h2)))] type RtcCntl = crate::peripherals::RTC_CNTL; #[cfg_attr(esp32, path = "rtc/esp32.rs")] #[cfg_attr(esp32c2, path = "rtc/esp32c2.rs")] #[cfg_attr(esp32c3, path = "rtc/esp32c3.rs")] #[cfg_attr(esp32c6, path = "rtc/esp32c6.rs")] +#[cfg_attr(esp32h2, path = "rtc/esp32h2.rs")] #[cfg_attr(esp32s2, path = "rtc/esp32s2.rs")] #[cfg_attr(esp32s3, path = "rtc/esp32s3.rs")] mod rtc; -#[cfg(esp32c6)] +#[cfg(any(esp32c6, esp32h2))] pub use rtc::RtcClock; extern "C" { @@ -42,7 +43,7 @@ extern "C" { pub fn software_reset(); } -#[cfg(not(esp32c6))] +#[cfg(not(any(esp32c6, esp32h2)))] #[allow(unused)] #[derive(Debug, Clone, Copy)] /// RTC SLOW_CLK frequency values @@ -53,20 +54,20 @@ pub(crate) enum RtcFastClock { RtcFastClock8m = 1, } -#[cfg(not(esp32c6))] +#[cfg(not(any(esp32c6, esp32h2)))] impl Clock for RtcFastClock { fn frequency(&self) -> HertzU32 { match self { RtcFastClock::RtcFastClockXtalD4 => HertzU32::Hz(40_000_000 / 4), #[cfg(any(esp32, esp32s2))] RtcFastClock::RtcFastClock8m => HertzU32::Hz(8_500_000), - #[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))] + #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] RtcFastClock::RtcFastClock8m => HertzU32::Hz(17_500_000), } } } -#[cfg(not(esp32c6))] +#[cfg(not(any(esp32c6, esp32h2)))] #[allow(unused)] #[derive(Debug, Clone, Copy)] /// RTC SLOW_CLK frequency values @@ -79,7 +80,7 @@ pub(crate) enum RtcSlowClock { RtcSlowClock8mD256 = 2, } -#[cfg(not(esp32c6))] +#[cfg(not(any(esp32c6, esp32h2)))] impl Clock for RtcSlowClock { fn frequency(&self) -> HertzU32 { match self { @@ -99,7 +100,7 @@ impl Clock for RtcSlowClock { } #[allow(unused)] -#[cfg(not(esp32c6))] +#[cfg(not(any(esp32c6, esp32h2)))] #[derive(Debug, Clone, Copy)] /// Clock source to be calibrated using rtc_clk_cal function pub(crate) enum RtcCalSel { @@ -117,7 +118,7 @@ pub(crate) enum RtcCalSel { pub struct Rtc<'d> { _inner: PeripheralRef<'d, RtcCntl>, pub rwdt: Rwdt, - #[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))] + #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] pub swd: Swd, } @@ -129,23 +130,23 @@ impl<'d> Rtc<'d> { Self { _inner: rtc_cntl.into_ref(), rwdt: Rwdt::default(), - #[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))] + #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] swd: Swd::new(), } } // TODO: implement for ESP32-C6 - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] pub fn estimate_xtal_frequency(&mut self) -> u32 { RtcClock::estimate_xtal_frequency() } } -#[cfg(not(esp32c6))] +#[cfg(not(any(esp32c6, esp32h2)))] /// RTC Watchdog Timer pub struct RtcClock; -#[cfg(not(esp32c6))] +#[cfg(not(any(esp32c6, esp32h2)))] /// RTC Watchdog Timer driver impl RtcClock { const CAL_FRACT: u32 = 19; @@ -162,7 +163,7 @@ impl RtcClock { /// /// When 8MHz/256 divided output is not needed, the divider should be /// disabled to reduce power consumption. - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] fn enable_8m(clk_8m_en: bool, d256_en: bool) { let rtc_cntl = unsafe { &*RTC_CNTL::PTR }; @@ -219,7 +220,7 @@ impl RtcClock { } /// Get the RTC_SLOW_CLK source - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] fn get_slow_freq() -> RtcSlowClock { let rtc_cntl = unsafe { &*RTC_CNTL::PTR }; let slow_freq = rtc_cntl.clk_conf.read().ana_clk_rtc_sel().bits(); @@ -232,7 +233,7 @@ impl RtcClock { } /// Select source for RTC_SLOW_CLK - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] fn set_slow_freq(slow_freq: RtcSlowClock) { unsafe { let rtc_cntl = &*RTC_CNTL::PTR; @@ -261,7 +262,7 @@ impl RtcClock { } /// Select source for RTC_FAST_CLK - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] fn set_fast_freq(fast_freq: RtcFastClock) { unsafe { let rtc_cntl = &*RTC_CNTL::PTR; @@ -279,7 +280,7 @@ impl RtcClock { /// Calibration of RTC_SLOW_CLK is performed using a special feature of /// TIMG0. This feature counts the number of XTAL clock cycles within a /// given number of RTC_SLOW_CLK cycles. - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] fn calibrate_internal(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 { // Except for ESP32, choosing RTC_CAL_RTC_MUX results in calibration of // the 150k RTC clock (90k on ESP32-S2) regardless of the currently selected @@ -454,7 +455,7 @@ impl RtcClock { match RtcClock::get_slow_freq() { RtcSlowClock::RtcSlowClockRtc => RtcCalSel::RtcCalRtcMux, RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal, - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] RtcSlowClock::RtcSlowClock8mD256 => RtcCalSel::RtcCal8mD256, }, 1024, @@ -467,7 +468,7 @@ impl RtcClock { } // TODO: implement for ESP32-C6 - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] fn estimate_xtal_frequency() -> u32 { // Number of 8M/256 clock cycles to use for XTAL frequency estimation. const XTAL_FREQ_EST_CYCLES: u32 = 10; @@ -524,9 +525,9 @@ impl Default for Rwdt { /// RTC Watchdog Timer driver impl Rwdt { pub fn listen(&mut self) { - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] let rtc_cntl = unsafe { &*RTC_CNTL::PTR }; - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] let rtc_cntl = unsafe { &*LP_WDT::PTR }; self.stg0_action = RwdtStageAction::RwdtStageActionInterrupt; @@ -549,9 +550,9 @@ impl Rwdt { } pub fn unlisten(&mut self) { - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] let rtc_cntl = unsafe { &*RTC_CNTL::PTR }; - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] let rtc_cntl = unsafe { &*LP_WDT::PTR }; self.stg0_action = RwdtStageAction::RwdtStageActionResetRtc; @@ -574,9 +575,9 @@ impl Rwdt { } pub fn clear_interrupt(&mut self) { - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] let rtc_cntl = unsafe { &*RTC_CNTL::PTR }; - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] let rtc_cntl = unsafe { &*LP_WDT::PTR }; self.set_write_protection(false); @@ -590,9 +591,9 @@ impl Rwdt { } pub fn is_interrupt_set(&self) -> bool { - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] let rtc_cntl = unsafe { &*RTC_CNTL::PTR }; - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] let rtc_cntl = unsafe { &*LP_WDT::PTR }; cfg_if::cfg_if! { @@ -606,10 +607,11 @@ impl Rwdt { /// Enable/disable write protection for WDT registers fn set_write_protection(&mut self, enable: bool) { - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] let rtc_cntl = unsafe { &*RTC_CNTL::PTR }; - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] let rtc_cntl = unsafe { &*LP_WDT::PTR }; + let wkey = if enable { 0u32 } else { 0x50D8_3AA1 }; rtc_cntl.wdtwprotect.write(|w| unsafe { w.bits(wkey) }); @@ -618,9 +620,9 @@ impl Rwdt { impl WatchdogDisable for Rwdt { fn disable(&mut self) { - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] let rtc_cntl = unsafe { &*RTC_CNTL::PTR }; - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] let rtc_cntl = unsafe { &*LP_WDT::PTR }; self.set_write_protection(false); @@ -641,9 +643,9 @@ impl WatchdogEnable for Rwdt { where T: Into, { - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] let rtc_cntl = unsafe { &*RTC_CNTL::PTR }; - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] let rtc_cntl = unsafe { &*LP_WDT::PTR }; let timeout_raw = (period.into().to_millis() * (RtcClock::cycles_to_1ms() as u64)) as u32; @@ -655,13 +657,13 @@ impl WatchdogEnable for Rwdt { .wdtconfig1 .modify(|_, w| w.wdt_stg0_hold().bits(timeout_raw)); - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] (&*LP_WDT::PTR).config1.modify(|_, w| { w.wdt_stg0_hold() .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) }); - #[cfg(not(any(esp32, esp32c6)))] + #[cfg(not(any(esp32, esp32c6, esp32h2)))] rtc_cntl.wdtconfig1.modify(|_, w| { w.wdt_stg0_hold() .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) @@ -691,9 +693,9 @@ impl WatchdogEnable for Rwdt { impl Watchdog for Rwdt { fn feed(&mut self) { - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] let rtc_cntl = unsafe { &*RTC_CNTL::PTR }; - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] let rtc_cntl = unsafe { &*LP_WDT::PTR }; self.set_write_protection(false); @@ -702,11 +704,11 @@ impl Watchdog for Rwdt { } } -#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))] +#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] /// Super Watchdog pub struct Swd; -#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))] +#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] /// Super Watchdog driver impl Swd { pub fn new() -> Self { @@ -715,14 +717,14 @@ impl Swd { /// Enable/disable write protection for WDT registers fn set_write_protection(&mut self, enable: bool) { - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] let rtc_cntl = unsafe { &*RTC_CNTL::PTR }; - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] let rtc_cntl = unsafe { &*LP_WDT::PTR }; - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] let wkey = if enable { 0u32 } else { 0x8F1D_312A }; - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] let wkey = if enable { 0u32 } else { 0x50D8_3AA1 }; rtc_cntl @@ -731,12 +733,12 @@ impl Swd { } } -#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))] +#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] impl WatchdogDisable for Swd { fn disable(&mut self) { - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] let rtc_cntl = unsafe { &*RTC_CNTL::PTR }; - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] let rtc_cntl = unsafe { &*LP_WDT::PTR }; self.set_write_protection(false); @@ -753,13 +755,11 @@ pub fn get_reset_reason(cpu: Cpu) -> Option { } pub fn get_wakeup_cause() -> SleepSource { - // FIXME: check s_light_sleep_wakeup - // https://github.com/espressif/esp-idf/blob/afbdb0f3ef195ab51690a64e22bfb8a5cd487914/components/esp_hw_support/sleep_modes.c#L1394 if get_reset_reason(Cpu::ProCpu).unwrap() != SocResetReason::CoreDeepSleep { return SleepSource::Undefined; } - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] let wakeup_cause = WakeupReason::from_bits_retain(unsafe { (&*crate::peripherals::PMU::PTR) .slp_wakeup_status0 @@ -767,7 +767,7 @@ pub fn get_wakeup_cause() -> SleepSource { .wakeup_cause() .bits() }); - #[cfg(not(any(esp32, esp32c6)))] + #[cfg(not(any(esp32, esp32c6, esp32h2)))] let wakeup_cause = WakeupReason::from_bits_retain(unsafe { (&*RTC_CNTL::PTR) .slp_wakeup_cause diff --git a/esp-hal-common/src/rtc_cntl/rtc/esp32h2.rs b/esp-hal-common/src/rtc_cntl/rtc/esp32h2.rs new file mode 100644 index 00000000000..85eec95ea42 --- /dev/null +++ b/esp-hal-common/src/rtc_cntl/rtc/esp32h2.rs @@ -0,0 +1,95 @@ +use fugit::HertzU32; +use strum::FromRepr; + +use crate::clock::Clock; + +pub(crate) fn init() { + todo!() +} + +pub(crate) fn configure_clock() { + todo!() +} + +// Terminology: +// +// CPU Reset: Reset CPU core only, once reset done, CPU will execute from +// reset vector +// Core Reset: Reset the whole digital system except RTC sub-system +// System Reset: Reset the whole digital system, including RTC sub-system +// Chip Reset: Reset the whole chip, including the analog part + +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromRepr)] +pub enum SocResetReason { + /// Power on reset + /// + /// In ESP-IDF this value (0x01) can *also* be `ChipBrownOut` or + /// `ChipSuperWdt`, however that is not really compatible with Rust-style + /// enums. + ChipPowerOn = 0x01, + /// Software resets the digital core by RTC_CNTL_SW_SYS_RST + CoreSw = 0x03, + /// Deep sleep reset the digital core + CoreDeepSleep = 0x05, + /// Main watch dog 0 resets digital core + CoreMwdt0 = 0x07, + /// Main watch dog 1 resets digital core + CoreMwdt1 = 0x08, + /// RTC watch dog resets digital core + CoreRtcWdt = 0x09, + /// Main watch dog 0 resets CPU 0 + Cpu0Mwdt0 = 0x0B, + /// Software resets CPU 0 by RTC_CNTL_SW_PROCPU_RST + Cpu0Sw = 0x0C, + /// RTC watch dog resets CPU 0 + Cpu0RtcWdt = 0x0D, + /// VDD voltage is not stable and resets the digital core + SysBrownOut = 0x0F, + /// RTC watch dog resets digital core and rtc module + SysRtcWdt = 0x10, + /// Main watch dog 1 resets CPU 0 + Cpu0Mwdt1 = 0x11, + /// Super watch dog resets the digital core and rtc module + SysSuperWdt = 0x12, + /// Glitch on clock resets the digital core and rtc module + SysClkGlitch = 0x13, + /// eFuse CRC error resets the digital core + CoreEfuseCrc = 0x14, + /// USB UART resets the digital core + CoreUsbUart = 0x15, + /// USB JTAG resets the digital core + CoreUsbJtag = 0x16, + /// Glitch on power resets the digital core + CorePwrGlitch = 0x17, +} + +/// RTC SLOW_CLK frequency values +#[derive(Debug, Clone, Copy)] +pub(crate) enum RtcFastClock {} + +impl Clock for RtcFastClock { + fn frequency(&self) -> HertzU32 { + todo!() + } +} + +/// RTC SLOW_CLK frequency values +#[derive(Debug, Clone, Copy, PartialEq)] +pub(crate) enum RtcSlowClock {} + +impl Clock for RtcSlowClock { + fn frequency(&self) -> HertzU32 { + todo!() + } +} + +/// RTC Watchdog Timer +pub struct RtcClock; + +/// RTC Watchdog Timer driver +impl RtcClock { + /// Calculate the necessary RTC_SLOW_CLK cycles to complete 1 millisecond. + pub(crate) fn cycles_to_1ms() -> u16 { + todo!() + } +} diff --git a/esp-hal-common/src/soc/esp32h2/efuse.rs b/esp-hal-common/src/soc/esp32h2/efuse.rs new file mode 100644 index 00000000000..2b53c682faa --- /dev/null +++ b/esp-hal-common/src/soc/esp32h2/efuse.rs @@ -0,0 +1,34 @@ +pub struct Efuse; + +impl Efuse { + /// Reads chip's MAC address from the eFuse storage. + /// + /// # Example + /// + /// ``` + /// let mac_address = Efuse::get_mac_address(); + /// writeln!( + /// serial_tx, + /// "MAC: {:#X}:{:#X}:{:#X}:{:#X}:{:#X}:{:#X}", + /// mac_address[0], + /// mac_address[1], + /// mac_address[2], + /// mac_address[3], + /// mac_address[4], + /// mac_address[5] + /// ); + /// ``` + pub fn get_mac_address() -> [u8; 6] { + todo!() + } + + /// Get status of SPI boot encryption. + pub fn get_flash_encryption() -> bool { + todo!() + } + + /// Get the multiplier for the timeout value of the RWDT STAGE 0 register. + pub fn get_rwdt_multiplier() -> u8 { + todo!() + } +} diff --git a/esp-hal-common/src/soc/esp32h2/gpio.rs b/esp-hal-common/src/soc/esp32h2/gpio.rs new file mode 100644 index 00000000000..1328a17bd6e --- /dev/null +++ b/esp-hal-common/src/soc/esp32h2/gpio.rs @@ -0,0 +1,30 @@ +use paste::paste; + +pub const NUM_PINS: usize = 0; // FIXME + +pub type OutputSignalType = u8; +pub const OUTPUT_SIGNAL_MAX: u8 = 0; // FIXME +pub const INPUT_SIGNAL_MAX: u8 = 0; // FIXME + +pub const ONE_INPUT: u8 = 0x1e; +pub const ZERO_INPUT: u8 = 0x1f; + +/// Peripheral input signals for the GPIO mux +#[allow(non_camel_case_types)] +#[derive(PartialEq, Copy, Clone)] +pub enum InputSignal {} + +/// Peripheral input signals for the GPIO mux +#[allow(non_camel_case_types)] +#[derive(PartialEq, Copy, Clone)] +pub enum OutputSignal {} + +// crate::gpio::gpio! {} + +// crate::gpio::analog! {} + +// TODO USB pins +// implement marker traits on USB pins +// impl crate::otg_fs::UsbSel for Gpio?? {} +// impl crate::otg_fs::UsbDp for Gpio12 {} +// impl crate::otg_fs::UsbDm for Gpio13 {} diff --git a/esp-hal-common/src/soc/esp32h2/mod.rs b/esp-hal-common/src/soc/esp32h2/mod.rs new file mode 100644 index 00000000000..310b8d7141c --- /dev/null +++ b/esp-hal-common/src/soc/esp32h2/mod.rs @@ -0,0 +1,8 @@ +pub mod efuse; +pub mod gpio; +pub mod peripherals; +pub mod radio_clocks; + +pub(crate) mod registers { + pub const INTERRUPT_MAP_BASE: u32 = 0x60010000; +} diff --git a/esp-hal-common/src/soc/esp32h2/peripherals.rs b/esp-hal-common/src/soc/esp32h2/peripherals.rs new file mode 100644 index 00000000000..ca30eceb480 --- /dev/null +++ b/esp-hal-common/src/soc/esp32h2/peripherals.rs @@ -0,0 +1,64 @@ +use esp32h2 as pac; +// We need to export this for users to use +pub use pac::Interrupt; + +// We need to export this in the hal for the drivers to use +pub(crate) use self::peripherals::*; + +crate::peripherals! { + // AES => true, + // APB_SARADC => true, + // ASSIST_DEBUG => true, + // DS => true, + // ECC => true, + EFUSE => true, + // GDMA => true, + // GPIO => true, + // HMAC => true, + // HP_APM => true, + // HP_SYS => true, + // I2C0 => true, + // I2C1 => true, + // I2S0 => true, + INTERRUPT_CORE0 => true, + INTPRI => true, + // IO_MUX => true, + // LEDC => true, + // LP_ANA => true, + // LP_AON => true, + // LP_APM => true, + LP_CLKRST => true, + // LP_PERI => true, + // LP_TIMER => true, + LP_WDT => true, + // MCPWM0 => true, + // MEM_MONITOR => true, + // MODEM_LPCON => true, + // MODEM_SYSCON => true, + // OTP_DEBUG => true, + // PARL_IO => true, + // PAU => true, + // PCNT => true, + PCR => true, + // PMU => true, + // Peripherals => true, + // RMT => true, + // RNG => true, + // RSA => true, + // SHA => true, + // SOC_ETM => true, + // SPI0 => true, + // SPI1 => true, + // SPI2 => true, + // SYSTIMER => true, + // TEE => true, + // TIMG0 => true, + // TIMG1 => true, + // TRACE => true, + // TWAI0 => true, + // UART0 => true, + // UART1 => true, + // UHCI0 => true, + // USB_DEVICE => true, + RADIO => false, +} diff --git a/esp-hal-common/src/soc/esp32h2/radio_clocks.rs b/esp-hal-common/src/soc/esp32h2/radio_clocks.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/esp-hal-common/src/soc/esp32h2/radio_clocks.rs @@ -0,0 +1 @@ + diff --git a/esp-hal-common/src/soc/mod.rs b/esp-hal-common/src/soc/mod.rs index 542c7f511c9..03e8e6ca7e5 100644 --- a/esp-hal-common/src/soc/mod.rs +++ b/esp-hal-common/src/soc/mod.rs @@ -4,6 +4,7 @@ pub use self::soc::*; #[cfg_attr(esp32c2, path = "esp32c2/mod.rs")] #[cfg_attr(esp32c3, path = "esp32c3/mod.rs")] #[cfg_attr(esp32c6, path = "esp32c6/mod.rs")] +#[cfg_attr(esp32h2, path = "esp32h2/mod.rs")] #[cfg_attr(esp32s2, path = "esp32s2/mod.rs")] #[cfg_attr(esp32s3, path = "esp32s3/mod.rs")] mod soc; diff --git a/esp-hal-common/src/system.rs b/esp-hal-common/src/system.rs index c2c98b69c9f..644cf175634 100755 --- a/esp-hal-common/src/system.rs +++ b/esp-hal-common/src/system.rs @@ -13,11 +13,11 @@ use crate::peripheral::PeripheralRef; #[cfg(esp32)] type SystemPeripheral = crate::peripherals::DPORT; -#[cfg(esp32c6)] +#[cfg(any(esp32c6, esp32h2))] type SystemPeripheral = crate::peripherals::PCR; -#[cfg(esp32c6)] +#[cfg(any(esp32c6, esp32h2))] type IntPri = crate::peripherals::INTPRI; -#[cfg(not(any(esp32, esp32c6)))] +#[cfg(not(any(esp32, esp32c6, esp32h2)))] type SystemPeripheral = crate::peripherals::SYSTEM; pub enum SoftwareInterrupt { @@ -79,15 +79,18 @@ pub enum Peripheral { #[cfg(rsa)] Rsa, } + pub struct SoftwareInterruptControl { _private: (), } + impl SoftwareInterruptControl { pub fn raise(&mut self, interrupt: SoftwareInterrupt) { - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] let system = unsafe { &*SystemPeripheral::PTR }; - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] let system = unsafe { &*IntPri::PTR }; + match interrupt { SoftwareInterrupt::SoftwareInterrupt0 => { system @@ -111,11 +114,13 @@ impl SoftwareInterruptControl { } } } + pub fn reset(&mut self, interrupt: SoftwareInterrupt) { - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32c6, esp32h2)))] let system = unsafe { &*SystemPeripheral::PTR }; - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] let system = unsafe { &*IntPri::PTR }; + match interrupt { SoftwareInterrupt::SoftwareInterrupt0 => { system @@ -146,7 +151,7 @@ pub struct PeripheralClockControl { _private: (), } -#[cfg(not(esp32c6))] +#[cfg(not(any(esp32c6, esp32h2)))] impl PeripheralClockControl { /// Enables and resets the given peripheral pub fn enable(&mut self, peripheral: Peripheral) { @@ -490,6 +495,16 @@ impl PeripheralClockControl { } } +#[cfg(esp32h2)] +impl PeripheralClockControl { + /// Enables and resets the given peripheral + pub fn enable(&mut self, peripheral: Peripheral) { + let system = unsafe { &*SystemPeripheral::PTR }; + + todo!() + } +} + /// Controls the configuration of the chip's clocks. pub struct SystemClockControl { _private: (), diff --git a/esp-hal-procmacros/Cargo.toml b/esp-hal-procmacros/Cargo.toml index a7a63697b0c..a5f91208270 100644 --- a/esp-hal-procmacros/Cargo.toml +++ b/esp-hal-procmacros/Cargo.toml @@ -34,5 +34,6 @@ esp32 = [] esp32c2 = [] esp32c3 = [] esp32c6 = [] +esp32h2 = [] esp32s2 = [] esp32s3 = [] diff --git a/esp-hal-procmacros/src/lib.rs b/esp-hal-procmacros/src/lib.rs index 246e38bbc02..ab422c5ad44 100644 --- a/esp-hal-procmacros/src/lib.rs +++ b/esp-hal-procmacros/src/lib.rs @@ -219,6 +219,8 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { let hal_crate = crate_name("esp32c3-hal"); #[cfg(feature = "esp32c6")] let hal_crate = crate_name("esp32c6-hal"); + #[cfg(feature = "esp32h2")] + let hal_crate = crate_name("esp32h2-hal"); #[cfg(feature = "esp32")] let hal_crate_name = Ident::new("esp32_hal", Span::call_site().into()); @@ -232,6 +234,8 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { let hal_crate_name = Ident::new("esp32c3_hal", Span::call_site().into()); #[cfg(feature = "esp32c6")] let hal_crate_name = Ident::new("esp32c6_hal", Span::call_site().into()); + #[cfg(feature = "esp32h2")] + let hal_crate_name = Ident::new("esp32h2_hal", Span::call_site().into()); let interrupt_in_hal_crate = match hal_crate { Ok(FoundCrate::Itself) => { diff --git a/esp-hal-smartled/Cargo.toml b/esp-hal-smartled/Cargo.toml index 1f1c9fb783b..38f8e854fa6 100644 --- a/esp-hal-smartled/Cargo.toml +++ b/esp-hal-smartled/Cargo.toml @@ -18,6 +18,7 @@ smart-leds-trait = "0.2.1" esp32 = ["esp-hal-common/esp32"] esp32c3 = ["esp-hal-common/esp32c3"] esp32c6 = ["esp-hal-common/esp32c6"] +esp32h2 = ["esp-hal-common/esp32h2"] esp32s2 = ["esp-hal-common/esp32s2"] esp32s3 = ["esp-hal-common/esp32s3"] diff --git a/esp-hal-smartled/src/lib.rs b/esp-hal-smartled/src/lib.rs index 171af7192fa..6e919f0e199 100644 --- a/esp-hal-smartled/src/lib.rs +++ b/esp-hal-smartled/src/lib.rs @@ -52,6 +52,8 @@ const SOURCE_CLK_FREQ: u32 = 40_000_000; const SOURCE_CLK_FREQ: u32 = 40_000_000; #[cfg(feature = "esp32c6")] const SOURCE_CLK_FREQ: u32 = 40_000_000; +#[cfg(feature = "esp32h2")] +const SOURCE_CLK_FREQ: u32 = 40_000_000; #[cfg(feature = "esp32s2")] const SOURCE_CLK_FREQ: u32 = 40_000_000; #[cfg(feature = "esp32s3")] diff --git a/esp32h2-hal/.cargo/config.toml b/esp32h2-hal/.cargo/config.toml new file mode 100644 index 00000000000..3e8a0bd0188 --- /dev/null +++ b/esp32h2-hal/.cargo/config.toml @@ -0,0 +1,11 @@ +[target.riscv32imac-unknown-none-elf] +runner = "espflash flash --monitor" +rustflags = [ + "-C", "link-arg=-Tlinkall.x", +] + +[build] +target = "riscv32imac-unknown-none-elf" + +[unstable] +build-std = [ "core" ] diff --git a/esp32h2-hal/Cargo.toml b/esp32h2-hal/Cargo.toml new file mode 100644 index 00000000000..b987b52570c --- /dev/null +++ b/esp32h2-hal/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "esp32h2-hal" +version = "0.1.0" +authors = [ + "Kirill Mikhailov " +] +edition = "2021" +rust-version = "1.60.0" +description = "HAL for ESP32-H2 microcontrollers" +repository = "https://github.com/esp-rs/esp-hal" +license = "MIT OR Apache-2.0" + +keywords = [ + "embedded", + "embedded-hal", + "esp", + "esp32h2", + "no-std", +] +categories = [ + "embedded", + "hardware-support", + "no-std", +] + +[dependencies] +cfg-if = "1.0.0" +embassy-time = { version = "0.1.0", features = ["nightly"], optional = true } +embedded-hal = { version = "0.2.7", features = ["unproven"] } +embedded-hal-1 = { version = "=1.0.0-alpha.9", optional = true, package = "embedded-hal" } +embedded-hal-async = { version = "0.2.0-alpha.0", optional = true } +embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true } +embedded-can = { version = "0.4.1", optional = true } +esp-hal-common = { version = "0.8.0", features = ["esp32h2"], path = "../esp-hal-common" } + +[dev-dependencies] +aes = "0.8.2" +critical-section = "1.1.1" +embassy-executor = { package = "embassy-executor", git = "https://github.com/embassy-rs/embassy/", rev = "cd9a65b", features = ["nightly", "integrated-timers"] } +embedded-graphics = "0.7.1" +esp-backtrace = { version = "0.7.0", features = ["esp32h2", "panic-handler", "exception-handler", "print-uart"] } +# esp-hal-smartled = { version = "0.1.0", features = ["esp32h2"], path = "../esp-hal-smartled" } +esp-println = { version = "0.4.0", features = ["esp32h2"] } +sha2 = { version = "0.10.6", default-features = false} +smart-leds = "0.3.0" +ssd1306 = "0.7.1" +static_cell = "1.0.0" + +[features] +default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"] +direct-boot = ["esp-hal-common/rv-init-data", "esp-hal-common/rv-init-rtc-data"] +eh1 = ["esp-hal-common/eh1", "dep:embedded-hal-1", "dep:embedded-hal-nb", "dep:embedded-can"] +rt = [] +ufmt = ["esp-hal-common/ufmt"] +vectored = ["esp-hal-common/vectored"] +async = ["esp-hal-common/async", "embedded-hal-async"] +embassy = ["esp-hal-common/embassy"] +embassy-time-systick = ["esp-hal-common/embassy-time-systick", "embassy-time/tick-hz-16_000_000"] +embassy-time-timg0 = ["esp-hal-common/embassy-time-timg0", "embassy-time/tick-hz-1_000_000"] + diff --git a/esp32h2-hal/README.md b/esp32h2-hal/README.md new file mode 100644 index 00000000000..4ef79560392 --- /dev/null +++ b/esp32h2-hal/README.md @@ -0,0 +1,76 @@ +# esp32h2-hal + + + +`no_std` HAL for the ESP32-H2 from Espressif. Implements a number of the traits defined by [embedded-hal](https://github.com/rust-embedded/embedded-hal). + +This device uses the RISC-V ISA, which is officially supported by the Rust compiler via the `riscv32imac-unknown-none-elf` target. Refer to the [Getting Started](#getting-started) section below for more information. + + +## License + +Licensed under either of: + +- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in +the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without +any additional terms or conditions. diff --git a/esp32h2-hal/build.rs b/esp32h2-hal/build.rs new file mode 100644 index 00000000000..b6161febd6d --- /dev/null +++ b/esp32h2-hal/build.rs @@ -0,0 +1,74 @@ +use std::{env, fs::File, io::Write, path::PathBuf}; + +#[cfg(feature = "direct-boot")] +fn main() { + // Put the linker script somewhere the linker can find it + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("ld/db-esp32h2-memory.x")) + .unwrap(); + + File::create(out.join("esp32h2-link.x")) + .unwrap() + .write_all(include_bytes!("ld/db-esp32h2-link.x")) + .unwrap(); + + File::create(out.join("riscv-link.x")) + .unwrap() + .write_all(include_bytes!("ld/db-riscv-link.x")) + .unwrap(); + + File::create(out.join("linkall.x")) + .unwrap() + .write_all(include_bytes!("ld/db-linkall.x")) + .unwrap(); + + println!("cargo:rustc-link-search={}", out.display()); + + // Only re-run the build script when memory.x is changed, + // instead of when any part of the source code changes. + println!("cargo:rerun-if-changed=ld/memory.x"); + + add_defaults(); +} + +#[cfg(not(feature = "direct-boot"))] +fn main() { + // Put the linker script somewhere the linker can find it + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("ld/bl-esp32h2-memory.x")) + .unwrap(); + + File::create(out.join("bl-riscv-link.x")) + .unwrap() + .write_all(include_bytes!("ld/bl-riscv-link.x")) + .unwrap(); + + File::create(out.join("linkall.x")) + .unwrap() + .write_all(include_bytes!("ld/bl-linkall.x")) + .unwrap(); + + println!("cargo:rustc-link-search={}", out.display()); + + // Only re-run the build script when memory.x is changed, + // instead of when any part of the source code changes. + println!("cargo:rerun-if-changed=ld/memory.x"); + + add_defaults(); +} + +fn add_defaults() { + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + File::create(out.join("rom-functions.x")) + .unwrap() + .write_all(include_bytes!("ld/rom-functions.x")) + .unwrap(); + + println!("cargo:rustc-link-search={}", out.display()); +} diff --git a/esp32h2-hal/examples/hello_world.rs b/esp32h2-hal/examples/hello_world.rs new file mode 100644 index 00000000000..c19c07dfefa --- /dev/null +++ b/esp32h2-hal/examples/hello_world.rs @@ -0,0 +1,21 @@ +#![no_std] +#![no_main] + +use esp32h2_hal::{ + clock::{ClockControl, CpuClock}, + entry, + peripherals::Peripherals, + prelude::*, +}; +use esp_backtrace as _; +use esp_println::println; + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take(); + let system = peripherals.PCR.split(); + let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock96MHz).freeze(); + + println!("Hello, world!"); + loop {} +} diff --git a/esp32h2-hal/ld/bl-esp32h2-memory.x b/esp32h2-hal/ld/bl-esp32h2-memory.x new file mode 100644 index 00000000000..c4a8be693af --- /dev/null +++ b/esp32h2-hal/ld/bl-esp32h2-memory.x @@ -0,0 +1,38 @@ +MEMORY +{ + /* MEMORY_MAP = [ + [0x00000000, 0x00010000, "PADDING"], + [0x42800000, 0x43000000, "DROM"], + [0x40800000, 0x40850000, "RAM"], + [0x40800000, 0x40850000, "BYTE_ACCESSIBLE"], + [0x4001С400, 0x40020000, "DROM_MASK"], + [0x40000000, 0x4001С400, "ROM_MASK"], + [0x42000000, 0x42800000, "ROM"], + [0x40800000, 0x40850000, "RAM"], + [0x50000000, 0x50001000, "RTC_RAM"], + [0x50000000, 0x50001000, "RTC_RAM"], + [0x600FE000, 0x60100000, "MEM_INTERNAL2"], + ] */ + + + /* 320K of on soc RAM, 16K reserved for cache */ + ICACHE : ORIGIN = 0x40800000, LENGTH = 16K + /* Instruction and Data RAM */ + RAM : ORIGIN = 0x40800000 + 16K, LENGTH = 320K - 16K + + /* External flash */ + /* Instruction and Data ROM */ + ROM : ORIGIN = 0x42000000, LENGTH = 0x400000 + + /* RTC fast memory (executable). Persists over deep sleep. */ + RTC_FAST : ORIGIN = 0x50000000, LENGTH = 16K /*- ESP_BOOTLOADER_RESERVE_RTC*/ +} + +REGION_ALIAS("ROTEXT", ROM); +REGION_ALIAS("RODATA", ROM); + +REGION_ALIAS("RWTEXT", RAM); +REGION_ALIAS("RWDATA", RAM); + +REGION_ALIAS("RTC_FAST_RWTEXT", RTC_FAST); +REGION_ALIAS("RTC_FAST_RWDATA", RTC_FAST); diff --git a/esp32h2-hal/ld/bl-linkall.x b/esp32h2-hal/ld/bl-linkall.x new file mode 100644 index 00000000000..e604dc6f8f8 --- /dev/null +++ b/esp32h2-hal/ld/bl-linkall.x @@ -0,0 +1,4 @@ +INCLUDE "memory.x" +INCLUDE "bl-riscv-link.x" +INCLUDE "hal-defaults.x" +INCLUDE "rom-functions.x" diff --git a/esp32h2-hal/ld/bl-riscv-link.x b/esp32h2-hal/ld/bl-riscv-link.x new file mode 100644 index 00000000000..701a1684e32 --- /dev/null +++ b/esp32h2-hal/ld/bl-riscv-link.x @@ -0,0 +1,83 @@ +ENTRY(_start) + +PROVIDE(_stext = ORIGIN(ROTEXT)); +PROVIDE(_stack_start = ORIGIN(RWDATA) + LENGTH(RWDATA)); +PROVIDE(_max_hart_id = 0); +PROVIDE(_hart_stack_size = 2K); +PROVIDE(_heap_size = 0); + +PROVIDE(UserSoft = DefaultHandler); +PROVIDE(SupervisorSoft = DefaultHandler); +PROVIDE(MachineSoft = DefaultHandler); +PROVIDE(UserTimer = DefaultHandler); +PROVIDE(SupervisorTimer = DefaultHandler); +PROVIDE(MachineTimer = DefaultHandler); +PROVIDE(UserExternal = DefaultHandler); +PROVIDE(SupervisorExternal = DefaultHandler); +PROVIDE(MachineExternal = DefaultHandler); + +PROVIDE(DefaultHandler = DefaultInterruptHandler); +PROVIDE(ExceptionHandler = DefaultExceptionHandler); + +/* The ESP32-C2 and ESP32-C3 have interrupt IDs 1-31, while the ESP32-C6 and ESP32-H2 has + IDs 0-31, so we much define the handler for the one additional interrupt + ID: */ +PROVIDE(interrupt0 = DefaultHandler); + +PROVIDE(__post_init = default_post_init); + +/* A PAC/HAL defined routine that should initialize custom interrupt controller if needed. */ +PROVIDE(_setup_interrupts = default_setup_interrupts); + +/* # Multi-processing hook function + fn _mp_hook() -> bool; + + This function is called from all the harts and must return true only for one hart, + which will perform memory initialization. For other harts it must return false + and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt). +*/ +PROVIDE(_mp_hook = default_mp_hook); + +/* # Start trap function override + By default uses the riscv crates default trap handler + but by providing the `_start_trap` symbol external crates can override. +*/ +PROVIDE(_start_trap = default_start_trap); + +/* Must be called __global_pointer$ for linker relaxations to work. */ +PROVIDE(__global_pointer$ = _data_start + 0x800); + +SECTIONS { + /* These symbols/functions need to be near eachother, group them together at the start of text */ + .text_init _stext : ALIGN(4) + { + KEEP(*(.init)); + KEEP(*(.init.rust)); + KEEP(*(.text.abort)); + KEEP(*(.trap)); + KEEP(*(.trap.rust)); + } > ROTEXT +} +INSERT BEFORE .text; + +SECTIONS { + /** + * Bootloader really wants to have separate segments for ROTEXT and RODATA + * Thus, we need to force a gap here. + */ + .text_gap (NOLOAD): { + . = . + 4; + . = ALIGN(4) + 0x20; + } > ROM +} +INSERT BEFORE .rodata; + +/* Shared sections - ordering matters */ +INCLUDE "text.x" +INCLUDE "rodata.x" +INCLUDE "rwdata.x" +INCLUDE "rwtext.x" +INCLUDE "rtc_fast.x" +/* End of Shared sections */ + +INCLUDE "debug.x" \ No newline at end of file diff --git a/esp32h2-hal/ld/db-esp32h2-link.x b/esp32h2-hal/ld/db-esp32h2-link.x new file mode 100644 index 00000000000..b2e740b39dc --- /dev/null +++ b/esp32h2-hal/ld/db-esp32h2-link.x @@ -0,0 +1,14 @@ +INCLUDE memory.x + +SECTIONS +{ + .header : AT(0) + { + LONG(0xaedb041d) + LONG(0xaedb041d) + } > ROM +} + +_stext = ORIGIN(ROM) + 8; + +INCLUDE riscv-link.x diff --git a/esp32h2-hal/ld/db-esp32h2-memory.x b/esp32h2-hal/ld/db-esp32h2-memory.x new file mode 100644 index 00000000000..869d65ee7f2 --- /dev/null +++ b/esp32h2-hal/ld/db-esp32h2-memory.x @@ -0,0 +1,39 @@ +MEMORY +{ + /* MEMORY_MAP = [ + [0x00000000, 0x00010000, "PADDING"], + [0x42800000, 0x43000000, "DROM"], + [0x40800000, 0x40850000, "DRAM"], + [0x40800000, 0x40850000, "BYTE_ACCESSIBLE"], + [0x4001С400, 0x40020000, "DROM_MASK"], + [0x40000000, 0x4001С400, "IROM_MASK"], + [0x42000000, 0x42800000, "IROM"], + [0x40800000, 0x40850000, "IRAM"], + [0x50000000, 0x50001000, "RTC_IRAM"], + [0x50000000, 0x50001000, "RTC_DRAM"], + [0x600FE000, 0x60100000, "MEM_INTERNAL2"], + ] */ + + + /* 320K of on soc RAM, 16K reserved for cache */ + ICACHE : ORIGIN = 0x40800000, LENGTH = 16K + + RAM : ORIGIN = 0x40800000 + 32K, LENGTH = 320K - 16K + + /* External flash */ + ROM : ORIGIN = 0x42000000, LENGTH = 0x400000 + + /* RTC fast memory (executable). Persists over deep sleep. */ + RTC_FAST : ORIGIN = 0x50000000, LENGTH = 16K /*- ESP_BOOTLOADER_RESERVE_RTC*/ +} + +REGION_ALIAS("REGION_TEXT", ROM); +REGION_ALIAS("REGION_RODATA", ROM); + +REGION_ALIAS("REGION_DATA", RAM); +REGION_ALIAS("REGION_BSS", RAM); +REGION_ALIAS("REGION_HEAP", RAM); +REGION_ALIAS("REGION_STACK", RAM); + +REGION_ALIAS("REGION_RWTEXT", RAM); +REGION_ALIAS("REGION_RTC_FAST", RTC_FAST); diff --git a/esp32h2-hal/ld/db-linkall.x b/esp32h2-hal/ld/db-linkall.x new file mode 100644 index 00000000000..e08ac551e0d --- /dev/null +++ b/esp32h2-hal/ld/db-linkall.x @@ -0,0 +1,3 @@ +INCLUDE "esp32h2-link.x" +INCLUDE "hal-defaults.x" +INCLUDE "rom-functions.x" diff --git a/esp32h2-hal/ld/db-riscv-link.x b/esp32h2-hal/ld/db-riscv-link.x new file mode 100644 index 00000000000..a06c44e52b2 --- /dev/null +++ b/esp32h2-hal/ld/db-riscv-link.x @@ -0,0 +1,237 @@ +ENTRY(_start) + +PROVIDE(_stext = ORIGIN(REGION_TEXT)); +PROVIDE(_stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK)); +PROVIDE(_max_hart_id = 0); +PROVIDE(_hart_stack_size = 2K); +PROVIDE(_heap_size = 0); + +PROVIDE(UserSoft = DefaultHandler); +PROVIDE(SupervisorSoft = DefaultHandler); +PROVIDE(MachineSoft = DefaultHandler); +PROVIDE(UserTimer = DefaultHandler); +PROVIDE(SupervisorTimer = DefaultHandler); +PROVIDE(MachineTimer = DefaultHandler); +PROVIDE(UserExternal = DefaultHandler); +PROVIDE(SupervisorExternal = DefaultHandler); +PROVIDE(MachineExternal = DefaultHandler); + +PROVIDE(DefaultHandler = DefaultInterruptHandler); +PROVIDE(ExceptionHandler = DefaultExceptionHandler); + +/* The ESP32-C2 and ESP32-C3 have interrupt IDs 1-31, while the ESP32-C6 has + IDs 0-31, so we much define the handler for the one additional interrupt + ID: */ +PROVIDE(interrupt0 = DefaultHandler); + +PROVIDE(__post_init = default_post_init); + +/* A PAC/HAL defined routine that should initialize custom interrupt controller if needed. */ +PROVIDE(_setup_interrupts = default_setup_interrupts); + +/* # Multi-processing hook function + fn _mp_hook() -> bool; + + This function is called from all the harts and must return true only for one hart, + which will perform memory initialization. For other harts it must return false + and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt). +*/ +PROVIDE(_mp_hook = default_mp_hook); + +/* # Start trap function override + By default uses the riscv crates default trap handler + but by providing the `_start_trap` symbol external crates can override. +*/ +PROVIDE(_start_trap = default_start_trap); + +SECTIONS +{ + .text.dummy (NOLOAD) : + { + /* This section is intended to make _stext address work */ + . = ABSOLUTE(_stext); + } > REGION_TEXT + + .text _stext : + { + /* Put reset handler first in .text section so it ends up as the entry */ + /* point of the program. */ + KEEP(*(.init)); + KEEP(*(.init.rust)); + KEEP(*(.text.abort)); + . = ALIGN(4); + KEEP(*(.trap)); + KEEP(*(.trap.rust)); + + *(.text .text.*); + _etext = .; + } > REGION_TEXT + + _text_size = _etext - _stext + 8; + .rodata ORIGIN(ROM) + _text_size : AT(_text_size) + { + _srodata = .; + *(.srodata .srodata.*); + *(.rodata .rodata.*); + + /* 4-byte align the end (VMA) of this section. + This is required by LLD to ensure the LMA of the following .data + section will have the correct alignment. */ + . = ALIGN(4); + _erodata = .; + } > REGION_RODATA + + _rodata_size = _erodata - _srodata + 8; + .data ORIGIN(RAM) : AT(_text_size + _rodata_size) + { + _data_start = .; + /* Must be called __global_pointer$ for linker relaxations to work. */ + PROVIDE(__global_pointer$ = . + 0x800); + *(.sdata .sdata.* .sdata2 .sdata2.*); + *(.data .data.*); + . = ALIGN(4); + _data_end = .; + } > REGION_DATA + + _data_size = _data_end - _data_start + 8; + .rwtext ORIGIN(REGION_RWTEXT) + _data_size : AT(_text_size + _rodata_size + _data_size){ + _srwtext = .; + *(.rwtext); + . = ALIGN(4); + _erwtext = .; + } > REGION_RWTEXT + _rwtext_size = _erwtext - _srwtext + 8; + + .rtc_fast.text : AT(_text_size + _rodata_size + _data_size + _rwtext_size) { + _srtc_fast_text = .; + *(.rtc_fast.literal .rtc_fast.text .rtc_fast.literal.* .rtc_fast.text.*) + . = ALIGN(4); + _ertc_fast_text = .; + } > REGION_RTC_FAST + _fast_text_size = _ertc_fast_text - _srtc_fast_text + 8; + + .rtc_fast.data : AT(_text_size + _rodata_size + _data_size + _rwtext_size + _fast_text_size) + { + _rtc_fast_data_start = ABSOLUTE(.); + *(.rtc_fast.data .rtc_fast.data.*) + . = ALIGN(4); + _rtc_fast_data_end = ABSOLUTE(.); + } > REGION_RTC_FAST + _rtc_fast_data_size = _rtc_fast_data_end - _rtc_fast_data_start + 8; + + .rtc_fast.bss (NOLOAD) : ALIGN(4) + { + _rtc_fast_bss_start = ABSOLUTE(.); + *(.rtc_fast.bss .rtc_fast.bss.*) + . = ALIGN(4); + _rtc_fast_bss_end = ABSOLUTE(.); + } > REGION_RTC_FAST + + .rtc_fast.noinit (NOLOAD) : ALIGN(4) + { + *(.rtc_fast.noinit .rtc_fast.noinit.*) + } > REGION_RTC_FAST + + .bss (NOLOAD) : + { + _bss_start = .; + *(.sbss .sbss.* .bss .bss.*); + . = ALIGN(4); + _bss_end = .; + } > REGION_BSS + + /* ### .uninit */ + .uninit (NOLOAD) : ALIGN(4) + { + . = ALIGN(4); + __suninit = .; + *(.uninit .uninit.*); + . = ALIGN(4); + __euninit = .; + } > REGION_BSS + + /* fictitious region that represents the memory available for the heap */ + .heap (NOLOAD) : + { + _sheap = .; + . += _heap_size; + . = ALIGN(4); + _eheap = .; + } > REGION_HEAP + + /* fictitious region that represents the memory available for the stack */ + .stack (NOLOAD) : + { + _estack = .; + . = ABSOLUTE(_stack_start); + _sstack = .; + } > REGION_STACK + + /* fake output .got section */ + /* Dynamic relocations are unsupported. This section is only used to detect + relocatable code in the input files and raise an error if relocatable code + is found */ + .got (INFO) : + { + KEEP(*(.got .got.*)); + } + + .eh_frame (INFO) : { KEEP(*(.eh_frame)) } + .eh_frame_hdr (INFO) : { *(.eh_frame_hdr) } +} + +PROVIDE(_sidata = _erodata + 8); +PROVIDE(_irwtext = ORIGIN(ROM) + _text_size + _rodata_size + _data_size); +PROVIDE(_irtc_fast_text = ORIGIN(ROM) + _text_size + _rodata_size + _data_size + _rwtext_size); +PROVIDE(_irtc_fast_data = ORIGIN(ROM) + _text_size + _rodata_size + _data_size + _rwtext_size + _fast_text_size); + +/* Do not exceed this mark in the error messages above | */ +ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, " +ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned"); + +ASSERT(ORIGIN(REGION_RODATA) % 4 == 0, " +ERROR(riscv-rt): the start of the REGION_RODATA must be 4-byte aligned"); + +ASSERT(ORIGIN(REGION_DATA) % 4 == 0, " +ERROR(riscv-rt): the start of the REGION_DATA must be 4-byte aligned"); + +ASSERT(ORIGIN(REGION_HEAP) % 4 == 0, " +ERROR(riscv-rt): the start of the REGION_HEAP must be 4-byte aligned"); + +ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, " +ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned"); + +ASSERT(ORIGIN(REGION_STACK) % 4 == 0, " +ERROR(riscv-rt): the start of the REGION_STACK must be 4-byte aligned"); + +ASSERT(_stext % 4 == 0, " +ERROR(riscv-rt): `_stext` must be 4-byte aligned"); + +ASSERT(_data_start % 4 == 0 && _data_end % 4 == 0, " +BUG(riscv-rt): .data is not 4-byte aligned"); + +ASSERT(_sidata % 4 == 0, " +BUG(riscv-rt): the LMA of .data is not 4-byte aligned"); + +ASSERT(_bss_start % 4 == 0 && _bss_end % 4 == 0, " +BUG(riscv-rt): .bss is not 4-byte aligned"); + +ASSERT(_sheap % 4 == 0, " +BUG(riscv-rt): start of .heap is not 4-byte aligned"); + +ASSERT(_stext + SIZEOF(.text) < ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT), " +ERROR(riscv-rt): The .text section must be placed inside the REGION_TEXT region. +Set _stext to an address smaller than 'ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT)'"); + +ASSERT(SIZEOF(.stack) > (_max_hart_id + 1) * _hart_stack_size, " +ERROR(riscv-rt): .stack section is too small for allocating stacks for all the harts. +Consider changing `_max_hart_id` or `_hart_stack_size`."); + +ASSERT(SIZEOF(.got) == 0, " +.got section detected in the input files. Dynamic relocations are not +supported. If you are linking to C code compiled using the `gcc` crate +then modify your build script to compile the C code _without_ the +-fPIC flag. See the documentation of the `gcc::Config.fpic` method for +details."); + +/* Do not exceed this mark in the error messages above | */ diff --git a/esp32h2-hal/ld/rom-functions.x b/esp32h2-hal/ld/rom-functions.x new file mode 100644 index 00000000000..35ba4a68169 --- /dev/null +++ b/esp32h2-hal/ld/rom-functions.x @@ -0,0 +1,14 @@ +ets_printf = 0x40000028; +ets_update_cpu_frequency = ets_update_cpu_frequency_rom; +PROVIDE(esp_rom_printf = ets_printf); +PROVIDE(cache_invalidate_icache_all = 0x40000620); +PROVIDE(cache_suspend_icache = 0x4000066c); +PROVIDE(cache_resume_icache = 0x40000670); +/* TODO PROVIDE(cache_ibus_mmu_set = 0x40000560); */ +/* TODO PROVIDE(cache_dbus_mmu_set = 0x40000564); */ +PROVIDE(ets_delay_us = 0x40000040); +PROVIDE(ets_update_cpu_frequency_rom = 0x40000048); +PROVIDE(rtc_get_reset_reason = 0x40000018); +ets_update_cpu_frequency = 0x40000048; +PROVIDE(software_reset = 0x40000090); +PROVIDE(software_reset_cpu = 0x40000094); diff --git a/esp32h2-hal/src/lib.rs b/esp32h2-hal/src/lib.rs new file mode 100644 index 00000000000..9c8f5599c2d --- /dev/null +++ b/esp32h2-hal/src/lib.rs @@ -0,0 +1,14 @@ +#![no_std] +#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")] + +pub use embedded_hal as ehal; +#[cfg(feature = "embassy")] +pub use esp_hal_common::embassy; +pub use esp_hal_common::*; + +// pub use self::gpio::IO; + +// /// Common module for analog functions +// pub mod analog { +// pub use esp_hal_common::analog::{AvailableAnalog, SarAdcExt}; +// }