From 34eadfcf280e954db158dce65f7fea4161a72118 Mon Sep 17 00:00:00 2001 From: Frederick Vollbrecht Date: Thu, 1 Aug 2024 19:18:32 +0200 Subject: [PATCH] add esp32p4 support --- src/cpu.rs | 13 ++- src/gpio.rs | 225 ++++++++++++++++++++++++++++++++++++++++++++++- src/i2s/pdm.rs | 95 ++++++++++++++++++-- src/interrupt.rs | 4 +- src/task.rs | 6 +- src/timer.rs | 6 +- 6 files changed, 330 insertions(+), 19 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 6a910f2d766..2826e22c55f 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -1,4 +1,4 @@ -#[cfg(any(esp32, esp32s3))] +#[cfg(any(esp32, esp32s3, esp32p4))] use core::arch::asm; use esp_idf_sys::*; @@ -12,7 +12,7 @@ pub const CORES: u32 = SOC_CPU_CORES_NUM; #[repr(C)] pub enum Core { Core0 = 0, // PRO on dual-core systems, the one and only CPU on single-core systems - #[cfg(any(esp32, esp32s3))] + #[cfg(any(esp32, esp32s3, esp32p4))] Core1 = 1, // APP on dual-core systems } @@ -34,7 +34,7 @@ impl From for Core { fn from(core: i32) -> Self { match core { 0 => Core::Core0, - #[cfg(any(esp32, esp32s3))] + #[cfg(any(esp32, esp32s3, esp32p4))] 1 => Core::Core1, _ => panic!(), } @@ -57,11 +57,16 @@ pub fn core() -> Core { #[cfg(any(esp32, esp32s3, esp32p4))] let mut core = 0; - #[cfg(any(esp32, esp32s3))] // TODO: Need a way to get the running core on esp32p4 in future + #[cfg(any(esp32, esp32s3))] unsafe { asm!("rsr.prid {0}", "extui {0},{0},13,1", out(reg) core); } + #[cfg(esp32p4)] + unsafe { + asm!("cssr {0} mhartid", out(reg) core); + } + match core { 0 => Core::Core0, #[cfg(any(esp32, esp32s3, esp32p4))] diff --git a/src/gpio.rs b/src/gpio.rs index d5a45fd3daf..868b15e9841 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1448,7 +1448,7 @@ fn gpio_reset_without_pull(pin: gpio_num_t) -> Result<(), EspError> { pull_up_en: esp_idf_sys::gpio_pullup_t_GPIO_PULLUP_DISABLE, pull_down_en: esp_idf_sys::gpio_pulldown_t_GPIO_PULLDOWN_DISABLE, intr_type: esp_idf_sys::gpio_int_type_t_GPIO_INTR_DISABLE, - #[cfg(all(esp32h2, not(esp_idf_version_major = "4")))] + #[cfg(all(any(esp32h2, esp32p4), not(esp_idf_version_major = "4")))] hys_ctrl_mode: esp_idf_sys::gpio_hys_ctrl_mode_t_GPIO_HYS_SOFT_DISABLE, }; @@ -2272,7 +2272,7 @@ mod chip { // TODO: Implement esp32c6 glitch filters -#[cfg(any(esp32c5, esp32c6, esp32p4))] // TODO: Implement proper pin layout for esp32c5 and esp32p4 +#[cfg(any(esp32c5, esp32c6))] // TODO: Implement proper pin layout for esp32c5 mod chip { #[cfg(feature = "alloc")] extern crate alloc; @@ -2407,3 +2407,224 @@ mod chip { } } } + +#[cfg(esp32p4)] // TODO: Implement esp32p4 fully - RTC & ADC etc TODO +mod chip { + #[cfg(feature = "alloc")] + extern crate alloc; + + #[cfg(feature = "alloc")] + use alloc::boxed::Box; + + use esp_idf_sys::*; + + use crate::interrupt::asynch::HalIsrNotification; + + use crate::adc::ADC1; + + use super::*; + + #[allow(clippy::type_complexity)] + #[cfg(feature = "alloc")] + pub(crate) static mut PIN_ISR_HANDLER: [Option>; 54] = + [PIN_ISR_INIT; 54]; + + #[allow(clippy::type_complexity)] + pub(crate) static PIN_NOTIF: [HalIsrNotification; 54] = [PIN_NOTIF_INIT; 54]; + + // TODO: Unknown RTC & ADC Pins + pin!(Gpio0:0, IO, RTC:0, ADC1:0, NODAC:0, NOTOUCH:0); + pin!(Gpio1:1, IO, RTC:1, ADC1:1, NODAC:0, NOTOUCH:0); + pin!(Gpio2:2, IO, RTC:2, ADC1:2, NODAC:0, NOTOUCH:0); + pin!(Gpio3:3, IO, RTC:3, ADC1:3, NODAC:0, NOTOUCH:0); + pin!(Gpio4:4, IO, RTC:4, ADC1:4, NODAC:0, NOTOUCH:0); + pin!(Gpio5:5, IO, RTC:5, ADC1:5, NODAC:0, NOTOUCH:0); + pin!(Gpio6:6, IO, RTC:6, ADC1:6, NODAC:0, NOTOUCH:0); + pin!(Gpio7:7, IO, RTC:7, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio8:8, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio9:9, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + + pin!(Gpio10:10, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio11:11, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio12:12, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio13:13, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio14:14, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio15:15, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio16:16, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio17:17, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio18:18, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio19:19, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + + pin!(Gpio20:20, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio21:21, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio22:22, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio23:23, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio24:24, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio25:25, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio26:26, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio27:27, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio28:28, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio29:29, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + + pin!(Gpio30:30, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio31:31, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio32:32, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio33:33, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio34:34, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio35:35, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio36:36, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio37:37, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio38:38, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio39:39, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + + pin!(Gpio40:40, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio41:41, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio42:42, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio43:43, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio44:44, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio45:45, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio46:46, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio47:47, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio48:48, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio49:49, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + + pin!(Gpio50:50, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio51:51, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio52:52, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio53:53, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + pin!(Gpio54:54, IO, NORTC:0, NOADC:0, NODAC:0, NOTOUCH:0); + + pub struct Pins { + pub gpio0: Gpio0, + pub gpio1: Gpio1, + pub gpio2: Gpio2, + pub gpio3: Gpio3, + pub gpio4: Gpio4, + pub gpio5: Gpio5, + pub gpio6: Gpio6, + pub gpio7: Gpio7, + pub gpio8: Gpio8, + pub gpio9: Gpio9, + + pub gpio10: Gpio10, + pub gpio11: Gpio11, + pub gpio12: Gpio12, + pub gpio13: Gpio13, + pub gpio14: Gpio14, + pub gpio15: Gpio15, + pub gpio16: Gpio16, + pub gpio17: Gpio17, + pub gpio18: Gpio18, + pub gpio19: Gpio19, + + pub gpio20: Gpio20, + pub gpio21: Gpio21, + pub gpio22: Gpio22, + pub gpio23: Gpio23, + pub gpio24: Gpio24, + pub gpio25: Gpio25, + pub gpio26: Gpio26, + pub gpio27: Gpio27, + pub gpio28: Gpio28, + pub gpio29: Gpio29, + + pub gpio30: Gpio30, + pub gpio31: Gpio31, + pub gpio32: Gpio32, + pub gpio33: Gpio33, + pub gpio34: Gpio34, + pub gpio35: Gpio35, + pub gpio36: Gpio36, + pub gpio37: Gpio37, + pub gpio38: Gpio38, + pub gpio39: Gpio39, + + pub gpio40: Gpio40, + pub gpio41: Gpio41, + pub gpio42: Gpio42, + pub gpio43: Gpio43, + pub gpio44: Gpio44, + pub gpio45: Gpio45, + pub gpio46: Gpio46, + pub gpio47: Gpio47, + pub gpio48: Gpio48, + pub gpio49: Gpio49, + + pub gpio50: Gpio50, + pub gpio51: Gpio51, + pub gpio52: Gpio52, + pub gpio53: Gpio53, + pub gpio54: Gpio54, + } + + impl Pins { + /// # Safety + /// + /// Care should be taken not to instantiate the Pins structure, if it is + /// already instantiated and used elsewhere + pub unsafe fn new() -> Self { + Self { + gpio0: Gpio0::new(), + gpio1: Gpio1::new(), + gpio2: Gpio2::new(), + gpio3: Gpio3::new(), + gpio4: Gpio4::new(), + gpio5: Gpio5::new(), + gpio6: Gpio6::new(), + gpio7: Gpio7::new(), + gpio8: Gpio8::new(), + gpio9: Gpio9::new(), + + gpio10: Gpio10::new(), + gpio11: Gpio11::new(), + gpio12: Gpio12::new(), + gpio13: Gpio13::new(), + gpio14: Gpio14::new(), + gpio15: Gpio15::new(), + gpio16: Gpio16::new(), + gpio17: Gpio17::new(), + gpio18: Gpio18::new(), + gpio19: Gpio19::new(), + + gpio20: Gpio20::new(), + gpio21: Gpio21::new(), + gpio22: Gpio22::new(), + gpio23: Gpio23::new(), + gpio24: Gpio24::new(), + gpio25: Gpio25::new(), + gpio26: Gpio26::new(), + gpio27: Gpio27::new(), + gpio28: Gpio28::new(), + gpio29: Gpio29::new(), + + gpio30: Gpio30::new(), + gpio31: Gpio31::new(), + gpio32: Gpio32::new(), + gpio33: Gpio33::new(), + gpio34: Gpio34::new(), + gpio35: Gpio35::new(), + gpio36: Gpio36::new(), + gpio37: Gpio37::new(), + gpio38: Gpio38::new(), + gpio39: Gpio39::new(), + + gpio40: Gpio40::new(), + gpio41: Gpio41::new(), + gpio42: Gpio42::new(), + gpio43: Gpio43::new(), + gpio44: Gpio44::new(), + gpio45: Gpio45::new(), + gpio46: Gpio46::new(), + gpio47: Gpio47::new(), + gpio48: Gpio48::new(), + gpio49: Gpio49::new(), + + gpio50: Gpio50::new(), + gpio51: Gpio51::new(), + gpio52: Gpio52::new(), + gpio53: Gpio53::new(), + gpio54: Gpio54::new(), + } + } + } +} diff --git a/src/i2s/pdm.rs b/src/i2s/pdm.rs index 3f0f2db22a6..1404a08978a 100644 --- a/src/i2s/pdm.rs +++ b/src/i2s/pdm.rs @@ -11,6 +11,7 @@ //! | ESP32-C3 | _not supported_* | I2S0, hardware version 2 | //! | ESP32-C6 | _not supported_* | I2S0, hardware version 2 | //! | ESP32-H2 | _not supported_* | I2S0, hardware version 2 | +//! | ESP32-P4 | I2S0 | I2S0, hardware version 2 | ???? //! //! \* These microcontrollers have PDM Rx capabilities but lack a PDM-to-PCM decoder required by the ESP-IDF SDK. //! @@ -325,7 +326,8 @@ pub(super) mod config { clk: PeripheralRef<'d, impl OutputPin>, din: PeripheralRef<'d, impl InputPin>, ) -> i2s_pdm_rx_gpio_config_t { - let mut dins: [gpio_num_t; SOC_I2S_PDM_MAX_RX_LINES] = [-1; SOC_I2S_PDM_MAX_RX_LINES]; + let mut dins: [gpio_num_t; SOC_I2S_PDM_MAX_RX_LINES as usize] = + [-1; SOC_I2S_PDM_MAX_RX_LINES as _]; dins[0] = din.pin(); let pins = i2s_pdm_rx_gpio_config_t__bindgen_ty_1 { dins }; @@ -358,11 +360,11 @@ pub(super) mod config { clk: PeripheralRef<'d, impl OutputPin>, dins: &[PeripheralRef<'d, impl InputPin>], ) -> i2s_pdm_rx_gpio_config_t { - let mut din_pins: [gpio_num_t; SOC_I2S_PDM_MAX_RX_LINES] = - [-1; SOC_I2S_PDM_MAX_RX_LINES]; + let mut din_pins: [gpio_num_t; SOC_I2S_PDM_MAX_RX_LINES as usize] = + [-1; SOC_I2S_PDM_MAX_RX_LINES as _]; for (i, din) in dins.iter().enumerate() { - if i >= SOC_I2S_PDM_MAX_RX_LINES { + if i >= SOC_I2S_PDM_MAX_RX_LINES as usize { break; } @@ -424,7 +426,7 @@ pub(super) mod config { /// /// Other microcontrollers do not support PDM receive mode, or do not have a PDM-to-PCM peripheral that allows for decoding /// the PDM data as required by ESP-IDF. - #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[derive(Clone, Copy, Debug)] pub struct PdmRxSlotConfig { /// I2S sample data bit width (valid data bits per sample). #[allow(dead_code)] @@ -441,8 +443,34 @@ pub(super) mod config { /// Are we using the left, right, or both data slots? #[allow(dead_code)] pub(super) slot_mask: PdmSlotMask, + + /// High pass filter + #[cfg(esp_idf_soc_i2s_supports_pdm_rx_hp_filter)] + pub(super) high_pass: Option, + } + + impl PartialEq for PdmRxSlotConfig { + #[cfg(not(esp_idf_soc_i2s_supports_pdm_rx_hp_filter))] + fn eq(&self, other: &Self) -> bool { + self.data_bit_width == other.data_bit_width + && self.slot_bit_width == other.slot_bit_width + && self.slot_mode == other.slot_mode + && self.slot_mask == other.slot_mask + } + + /// Note: Ignoring the high_pass filter that contains a f32 for eq compairson and only checking if its set or not. + #[cfg(esp_idf_soc_i2s_supports_pdm_rx_hp_filter)] + fn eq(&self, other: &Self) -> bool { + self.data_bit_width == other.data_bit_width + && self.slot_bit_width == other.slot_bit_width + && self.slot_mode == other.slot_mode + && self.slot_mask == other.slot_mask + && self.high_pass.is_some() == other.high_pass.is_some() + } } + impl Eq for PdmRxSlotConfig {} + impl PdmRxSlotConfig { /// Configure the PDM mode channel receive slot configuration for the specified bits per sample and slot mode /// in 2 slots. @@ -461,6 +489,8 @@ pub(super) mod config { slot_bit_width: SlotBitWidth::Auto, slot_mode, slot_mask, + #[cfg(esp_idf_soc_i2s_supports_pdm_rx_hp_filter)] + high_pass: None, } } @@ -486,6 +516,13 @@ pub(super) mod config { self } + #[cfg(esp_idf_soc_i2s_supports_pdm_rx_hp_filter)] + /// Set the PDM high pass filter + pub fn high_pass_filter(mut self, filter: Option) -> Self { + self.high_pass = filter; + self + } + /// Convert this PDM mode channel receive slot configuration into the ESP-IDF SDK `i2s_pdm_rx_slot_config_t` /// representation. #[cfg(esp_idf_soc_i2s_supports_pdm_rx)] @@ -496,6 +533,20 @@ pub(super) mod config { slot_bit_width: self.slot_bit_width.as_sdk(), slot_mode: self.slot_mode.as_sdk(), slot_mask: self.slot_mask.as_sdk(), + #[cfg(esp_idf_soc_i2s_supports_pdm_rx_hp_filter)] + hp_en: self.high_pass.is_some(), + #[cfg(esp_idf_soc_i2s_supports_pdm_rx_hp_filter)] + hp_cut_off_freq_hz: if let Some(filter) = self.high_pass { + filter.cut_off_freq + } else { + 185.0 + }, + #[cfg(esp_idf_soc_i2s_supports_pdm_rx_hp_filter)] + amplify_num: if let Some(filter) = self.high_pass { + filter.amplify_num + } else { + 1 + }, } } } @@ -567,6 +618,40 @@ pub(super) mod config { } } + /// PDM RX High Pass Filter + #[derive(Clone, Copy, Debug, PartialEq)] + pub struct HighPassFilter { + /// High pass filter cut-off frequency, range 23.3Hz ~ 185Hz + pub(super) cut_off_freq: f32, + + /// The amplification number of the final conversion result + /// + /// The data that have converted from PDM to PCM module, will time `amplify_num` additionally to amplify the final result. + /// Note that it's only a multiplier of the digital PCM data, not the gain of the analog signal. + /// range 1~15, default 1 + pub(super) amplify_num: u32, + } + + impl HighPassFilter { + /// Set the Filter cut off Frequency. + /// + /// Note: Range between 23.3Hz ~ 185Hz + pub fn cut_off_freq(cut_off_freq: f32) -> Self { + Self { + cut_off_freq, + amplify_num: 1, + } + } + + /// Set the amplification number of the final conversion result + /// + /// Range: 1-15 + pub fn amplify_number(mut self, amplify_num: u32) -> Self { + self.amplify_num = amplify_num; + self + } + } + /// The I2s pulse density modulation (PDM) mode transmit clock configuration. /// /// # Note diff --git a/src/interrupt.rs b/src/interrupt.rs index 6fa9b645226..0dd96588773 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -187,7 +187,7 @@ fn enter(cs: &IsrCriticalSection) { } } -#[cfg(not(any(esp32, esp32s2, esp32s3, esp32p4)))] +#[cfg(not(any(esp32, esp32s2, esp32s3)))] #[inline(always)] #[link_section = ".iram1.interrupt_exit"] fn exit(_cs: &IsrCriticalSection) { @@ -196,7 +196,7 @@ fn exit(_cs: &IsrCriticalSection) { } } -#[cfg(any(esp32, esp32s2, esp32s3, esp32p4))] +#[cfg(any(esp32, esp32s2, esp32s3))] #[inline(always)] #[link_section = ".iram1.interrupt_exit"] fn exit(cs: &IsrCriticalSection) { diff --git a/src/task.rs b/src/task.rs index f2f196c0ca3..2fe73d86f38 100644 --- a/src/task.rs +++ b/src/task.rs @@ -91,17 +91,17 @@ pub fn do_yield() { if let Some((yielder, arg)) = interrupt::get_isr_yielder() { yielder(arg); } else { - #[cfg(any(esp32c3, esp32c2, esp32h2, esp32c5, esp32c6))] + #[cfg(any(esp32c3, esp32c2, esp32h2, esp32c5, esp32c6, esp32p4))] vPortYieldFromISR(); #[cfg(all( - not(any(esp32c3, esp32c2, esp32h2, esp32c5, esp32c6)), + not(any(esp32c3, esp32c2, esp32h2, esp32c5, esp32c6, esp32p4)), esp_idf_version_major = "4" ))] vPortEvaluateYieldFromISR(0); #[cfg(all( - not(any(esp32c3, esp32c2, esp32h2, esp32c5, esp32c6)), + not(any(esp32c3, esp32c2, esp32h2, esp32c5, esp32c6, esp32p4)), not(esp_idf_version_major = "4") ))] _frxt_setup_switch(); diff --git a/src/timer.rs b/src/timer.rs index f272b7ae133..b85d26d394e 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -79,7 +79,7 @@ pub mod config { #[cfg(esp32h2)] #[default] PLL48, - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32p4))] #[default] PLL80, #[cfg(not(esp32))] @@ -101,7 +101,7 @@ pub mod config { ClockSource::PLL48 => { esp_idf_sys::soc_periph_tg_clk_src_legacy_t_TIMER_SRC_CLK_PLL_F48M } - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32p4))] ClockSource::PLL80 => { esp_idf_sys::soc_periph_tg_clk_src_legacy_t_TIMER_SRC_CLK_PLL_F80M } @@ -218,7 +218,7 @@ impl<'d> TimerDriver<'d> { { hz = 48_000_000 / self.divider; } - #[cfg(esp32c6)] //PLL80 + #[cfg(any(esp32c6, esp32p4))] //PLL80 { hz = 80_000_000 / self.divider; }