diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 068071c085f..6d25180f22d 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -19,12 +19,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - ESP32-C6: Support lp-core as wake-up source (#1723) - Add support for GPIO wake-up source (#1724) - dma: add Mem2Mem to support memory to memory transfer (#1738) +- Add `uart` wake source (#1727) ### Fixed - TIMG: Fix interrupt handler setup (#1714) - Fix `sleep_light` for ESP32-C6 (#1720) - ROM Functions: Fix address of `ets_update_cpu_frequency_rom` (#1722) +- Fix `regi2c_*` functions for `esp32h2` (#1737) ### Changed diff --git a/esp-hal/src/clock/clocks_ll/esp32h2.rs b/esp-hal/src/clock/clocks_ll/esp32h2.rs index 311fc6ea9d1..0e82606e4b8 100644 --- a/esp-hal/src/clock/clocks_ll/esp32h2.rs +++ b/esp-hal/src/clock/clocks_ll/esp32h2.rs @@ -31,26 +31,21 @@ 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_PMU: 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 I2C_MST_ANA_CONF1_M: u32 = 0x00FFFFFF; +const I2C_MST_ANA_CONF1_REG: u32 = I2C_MST_I2C0_CTRL_REG + 0x1c; + +const REGI2C_BBPLL_RD_MASK: u32 = !(1 << 7) & I2C_MST_ANA_CONF1_M; +const REGI2C_BIAS_RD_MASK: u32 = !(1 << 6) & I2C_MST_ANA_CONF1_M; +const REGI2C_DIG_REG_RD_MASK: u32 = !(1 << 10) & I2C_MST_ANA_CONF1_M; +const REGI2C_ULP_CAL_RD_MASK: u32 = !(1 << 8) & I2C_MST_ANA_CONF1_M; +const REGI2C_SAR_I2C_RD_MASK: u32 = !(1 << 9) & I2C_MST_ANA_CONF1_M; const REGI2C_RTC_SLAVE_ID_V: u8 = 0xFF; const REGI2C_RTC_SLAVE_ID_S: u8 = 0; @@ -61,7 +56,7 @@ 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; +const I2C_MST_I2C0_CTRL_REG: u32 = 0x600AD800; const REGI2C_RTC_BUSY: u32 = 1 << 25; pub(crate) fn esp32h2_rtc_bbpll_configure(_xtal_freq: XtalClock, _pll_freq: PllClock) { @@ -239,33 +234,28 @@ fn clk_ll_bus_update() { } 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); + let modem_lpcon = unsafe { &*crate::peripherals::MODEM_LPCON::ptr() }; - // 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, - ); - } + modem_lpcon + .clk_conf() + .modify(|_, w| w.clk_i2c_mst_en().set_bit()); // Before config I2C register, enable corresponding slave. match block { - REGI2C_BBPLL => { - reg_set_bit(I2C_MST_ANA_CONF2_REG, REGI2C_BBPLL_DEVICE_EN); + v if v == REGI2C_BBPLL => { + reg_set_bit(I2C_MST_ANA_CONF1_REG, REGI2C_BBPLL_RD_MASK); } - REGI2C_BIAS => { - reg_set_bit(I2C_MST_ANA_CONF2_REG, REGI2C_BIAS_DEVICE_EN); + v if v == REGI2C_BIAS => { + reg_set_bit(I2C_MST_ANA_CONF1_REG, REGI2C_BIAS_RD_MASK); } - REGI2C_PMU_REG => { - reg_set_bit(I2C_MST_ANA_CONF2_REG, REGI2C_PMU_DEVICE_EN); + v if v == REGI2C_PMU => { + reg_set_bit(I2C_MST_ANA_CONF1_REG, REGI2C_DIG_REG_RD_MASK); } - REGI2C_ULP_CAL => { - reg_set_bit(I2C_MST_ANA_CONF2_REG, REGI2C_ULP_CAL_DEVICE_EN); + v if v == REGI2C_ULP_CAL => { + reg_set_bit(I2C_MST_ANA_CONF1_REG, REGI2C_ULP_CAL_RD_MASK); } - REGI2C_SAR_I2C => { - reg_set_bit(I2C_MST_ANA_CONF2_REG, REGI2C_SAR_I2C_DEVICE_EN); + v if v == REGI2C_SAR_I2C => { + reg_set_bit(I2C_MST_ANA_CONF1_REG, REGI2C_SAR_I2C_RD_MASK); } _ => (), } @@ -273,20 +263,20 @@ fn regi2c_enable_block(block: u8) { fn regi2c_disable_block(block: u8) { match block { - REGI2C_BBPLL => { - reg_clr_bit(I2C_MST_ANA_CONF2_REG, REGI2C_BBPLL_DEVICE_EN); + v if v == REGI2C_BBPLL => { + reg_clr_bit(I2C_MST_ANA_CONF1_REG, REGI2C_BBPLL_RD_MASK); } - REGI2C_BIAS => { - reg_clr_bit(I2C_MST_ANA_CONF2_REG, REGI2C_BIAS_DEVICE_EN); + v if v == REGI2C_BIAS => { + reg_clr_bit(I2C_MST_ANA_CONF1_REG, REGI2C_BIAS_RD_MASK); } - REGI2C_PMU_REG => { - reg_clr_bit(I2C_MST_ANA_CONF2_REG, REGI2C_PMU_DEVICE_EN); + v if v == REGI2C_PMU => { + reg_clr_bit(I2C_MST_ANA_CONF1_REG, REGI2C_DIG_REG_RD_MASK); } - REGI2C_ULP_CAL => { - reg_clr_bit(I2C_MST_ANA_CONF2_REG, REGI2C_ULP_CAL_DEVICE_EN); + v if v == REGI2C_ULP_CAL => { + reg_clr_bit(I2C_MST_ANA_CONF1_REG, REGI2C_ULP_CAL_RD_MASK); } - REGI2C_SAR_I2C => { - reg_clr_bit(I2C_MST_ANA_CONF2_REG, REGI2C_SAR_I2C_DEVICE_EN); + v if v == REGI2C_SAR_I2C => { + reg_clr_bit(I2C_MST_ANA_CONF1_REG, REGI2C_SAR_I2C_RD_MASK); } _ => (), } @@ -323,6 +313,8 @@ pub(crate) fn regi2c_write_mask(block: u8, _host_id: u8, reg_add: u8, msb: u8, l regi2c_enable_block(block); // Read the i2c bus register + while reg_get_bit(I2C_MST_I2C0_CTRL_REG, REGI2C_RTC_BUSY) != 0 {} + 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; diff --git a/esp-hal/src/rtc_cntl/sleep/mod.rs b/esp-hal/src/rtc_cntl/sleep/mod.rs index d167aad2789..48b2e19d3f4 100644 --- a/esp-hal/src/rtc_cntl/sleep/mod.rs +++ b/esp-hal/src/rtc_cntl/sleep/mod.rs @@ -181,6 +181,71 @@ impl WakeSource for GpioWakeupSource { } } +macro_rules! uart_wakeup_impl { + ($num:literal) => { + paste::paste! { + #[doc = concat!("UART", $num, " wakeup source")] + /// + /// The chip can be woken up by reverting RXD for multiple cycles until the + /// number of rising edges is equal to or greater than the given value. + /// + /// Note that the character which triggers wakeup (and any characters before + /// it) will not be received by the UART after wakeup. This means that the + /// external device typically needs to send an extra character to trigger + /// wakeup before sending the data. + /// + /// After waking-up from UART, you should send some extra data through the UART + /// port in Active mode, so that the internal wakeup indication signal can be + /// cleared. Otherwise, the next UART wake-up would trigger with two less + /// rising edges than the configured threshold value. + /// + /// Wakeup from light sleep takes some time, so not every character sent to the + /// UART can be received by the application. + /// + /// This wakeup source can be used to wake up from light sleep only. + pub struct [< Uart $num WakeupSource >] { + threshold: u16, + } + + impl [< Uart $num WakeupSource >] { + #[doc = concat!("Create a new instance of UART", $num, " wakeup source>") ] + /// + /// # Panics + /// + /// Panics if `threshold` is out of bounds. + pub fn new(threshold: u16) -> Self { + if threshold > 1023 { + panic!("Invalid threshold"); + } + Self { threshold } + } + } + + impl WakeSource for [< Uart $num WakeupSource >] { + fn apply(&self, _rtc: &Rtc, triggers: &mut WakeTriggers, _sleep_config: &mut RtcSleepConfig) { + triggers.[< set_uart $num >](true); + let uart = unsafe { crate::peripherals::[< UART $num >]::steal() }; + + #[cfg(any(esp32, esp32s2, esp32s3, esp32c2, esp32c3))] + uart.sleep_conf() + .modify(|_, w| unsafe { w.active_threshold().bits(self.threshold) }); + + #[cfg(not(any(esp32, esp32s2, esp32s3, esp32c2, esp32c3)))] + uart.sleep_conf2().modify(|_, w| unsafe { + w.wk_mode_sel() + .bits(0) + .active_threshold() + .bits(self.threshold) + }); + } + } + } + }; +} + +uart_wakeup_impl!(0); +uart_wakeup_impl!(1); + #[cfg(not(pmu))] bitfield::bitfield! { #[derive(Default, Clone, Copy)]