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 1ef21d0ead7..356329cb66d 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -51,10 +51,10 @@ ufmt-write = { version = "0.1.0", optional = true } # Each supported device MUST have its PAC included below along with a # corresponding feature. esp32 = { version = "0.23.0", features = ["critical-section"], optional = true } -esp32c2 = { version = "0.10.0", features = ["critical-section"], optional = true } -esp32c3 = { version = "0.13.0", features = ["critical-section"], optional = true } -esp32c6 = { version = "0.3.0", features = ["critical-section"], optional = true } -esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "3db0042", package = "esp32h2", 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 } diff --git a/esp-hal-common/devices/esp32h2.toml b/esp-hal-common/devices/esp32h2.toml index f3d47cf4266..6bd7a57b81a 100644 --- a/esp-hal-common/devices/esp32h2.toml +++ b/esp-hal-common/devices/esp32h2.toml @@ -1,5 +1,5 @@ [device] -arch = "riscv" +arch = "riscv" cores = "single_core" peripherals = [ @@ -18,8 +18,8 @@ peripherals = [ # "i2c0", # "i2c1", # "i2s0", - # "interrupt_core0", - # "intpri", + "interrupt_core0", + "intpri", # "io_mux", # "ledc", # "lp_ana", @@ -58,4 +58,8 @@ peripherals = [ # "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 index 74a74b9d027..8cd6dabd07b 100644 --- a/esp-hal-common/src/clock/clocks_ll/esp32h2.rs +++ b/esp-hal-common/src/clock/clocks_ll/esp32h2.rs @@ -1,25 +1,360 @@ -use crate::clock::{ApbClock, CpuClock, PllClock, XtalClock}; +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) { - todo!() + 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() { - todo!() + 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) { - todo!() + 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) { - todo!() + 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) { - todo!() + 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 b5d3b8d106f..193dd5cea83 100644 --- a/esp-hal-common/src/clock/mod.rs +++ b/esp-hal-common/src/clock/mod.rs @@ -31,6 +31,8 @@ pub trait Clock { #[derive(Debug, Clone, Copy)] pub enum CpuClock { Clock80MHz, + #[cfg(esp32h2)] + Clock96MHz, #[cfg(esp32c2)] Clock120MHz, #[cfg(not(esp32c2))] @@ -44,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))] @@ -437,7 +441,15 @@ impl<'d> ClockControl<'d> { pub fn boot_defaults( clock_control: impl Peripheral

+ 'd, ) -> ClockControl<'d> { - todo!() + 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. @@ -446,7 +458,31 @@ impl<'d> ClockControl<'d> { clock_control: impl Peripheral

+ 'd, cpu_clock_speed: CpuClock, ) -> ClockControl<'d> { - todo!() + 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), + }, + } } } diff --git a/esp-hal-common/src/rtc_cntl/rtc/esp32h2.rs b/esp-hal-common/src/rtc_cntl/rtc/esp32h2.rs index b75a5af0b17..85eec95ea42 100644 --- a/esp-hal-common/src/rtc_cntl/rtc/esp32h2.rs +++ b/esp-hal-common/src/rtc_cntl/rtc/esp32h2.rs @@ -20,7 +20,48 @@ pub(crate) fn configure_clock() { // Chip Reset: Reset the whole chip, including the analog part #[derive(Debug, Clone, Copy, PartialEq, Eq, FromRepr)] -pub enum SocResetReason {} +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)] diff --git a/esp-hal-common/src/soc/esp32h2/mod.rs b/esp-hal-common/src/soc/esp32h2/mod.rs index 8c121ca6b9d..310b8d7141c 100644 --- a/esp-hal-common/src/soc/esp32h2/mod.rs +++ b/esp-hal-common/src/soc/esp32h2/mod.rs @@ -4,5 +4,5 @@ pub mod peripherals; pub mod radio_clocks; pub(crate) mod registers { - pub const INTERRUPT_MAP_BASE: u32 = 0x0; // FIXME + 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 index 5931c83dd5b..ca30eceb480 100644 --- a/esp-hal-common/src/soc/esp32h2/peripherals.rs +++ b/esp-hal-common/src/soc/esp32h2/peripherals.rs @@ -20,8 +20,8 @@ crate::peripherals! { // I2C0 => true, // I2C1 => true, // I2S0 => true, - // INTERRUPT_CORE0 => true, - // INTPRI => true, + INTERRUPT_CORE0 => true, + INTPRI => true, // IO_MUX => true, // LEDC => true, // LP_ANA => true, diff --git a/esp-hal-common/src/system.rs b/esp-hal-common/src/system.rs index beaa9772a20..644cf175634 100755 --- a/esp-hal-common/src/system.rs +++ b/esp-hal-common/src/system.rs @@ -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 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}; +// }