diff --git a/esp-hal-common/.vscode/settings.json b/esp-hal-common/.vscode/settings.json index 0c529ec6a..293965674 100644 --- a/esp-hal-common/.vscode/settings.json +++ b/esp-hal-common/.vscode/settings.json @@ -1,6 +1,6 @@ { "rust-analyzer.cargo.features": [ - "esp32s3" + "esp32s2" ], "rust-analyzer.cargo.allFeatures": false, "editor.formatOnSave": true, @@ -10,12 +10,12 @@ "cargo", "check", "--features", - "esp32s3", + "esp32s2", "--message-format=json", "-Z", "build-std=core", "--target", - "xtensa-esp32s3-none-elf", + "xtensa-esp32s2-none-elf", "--examples", "--lib", ], diff --git a/esp-hal-common/src/analog/adc/esp32.rs b/esp-hal-common/src/analog/adc/esp32.rs new file mode 100644 index 000000000..343482b41 --- /dev/null +++ b/esp-hal-common/src/analog/adc/esp32.rs @@ -0,0 +1,394 @@ +use core::marker::PhantomData; + +use embedded_hal::adc::{Channel, OneShot}; + +use crate::{ + analog::{ADC1, ADC2}, + pac::{RTCIO, SENS}, +}; + +/// The sampling/readout resolution of the ADC +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum Resolution { + Resolution9Bit = 0b00, + Resolution10Bit = 0b01, + Resolution11Bit = 0b10, + Resolution12Bit = 0b11, +} + +/// The attenuation of the ADC pin +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum Attenuation { + Attenuation0dB = 0b00, + Attenuation2p5dB = 0b01, + Attenuation6dB = 0b10, + Attenuation11dB = 0b11, +} + +pub struct AdcConfig { + pub resolution: Resolution, + pub attenuations: [Option; 10], + _phantom: PhantomData, +} + +impl AdcConfig +where + ADCI: RegisterAccess, +{ + pub fn new() -> AdcConfig { + Self::default() + } + + pub fn enable_pin>( + &mut self, + _pin: &PIN, + attenuation: Attenuation, + ) { + self.attenuations[PIN::channel() as usize] = Some(attenuation); + } +} + +impl Default for AdcConfig { + fn default() -> Self { + AdcConfig { + resolution: Resolution::Resolution12Bit, + attenuations: [None; 10], + _phantom: PhantomData::default(), + } + } +} + +pub trait RegisterAccess { + fn set_bit_width(resolution: u8); + + fn set_sample_bit(resolution: u8); + + fn set_attenuation(channel: usize, attenuation: u8); + + fn clear_dig_force(); + + fn set_start_force(); + + fn set_en_pad_force(); + + fn set_en_pad(channel: u8); + + fn clear_start_sar(); + + fn set_start_sar(); + + fn read_done_sar() -> bool; + + fn read_data_sar() -> u16; +} + +impl RegisterAccess for ADC1 { + fn set_bit_width(resolution: u8) { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_start_force + .modify(|_, w| unsafe { w.sar1_bit_width().bits(resolution) }); + } + + fn set_sample_bit(resolution: u8) { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_read_ctrl + .modify(|_, w| unsafe { w.sar1_sample_bit().bits(resolution) }); + } + + fn set_attenuation(channel: usize, attenuation: u8) { + let sensors = unsafe { &*SENS::ptr() }; + sensors.sar_atten1.modify(|r, w| { + let new_value = (r.bits() & !(0b11 << (channel * 2))) + | (((attenuation as u8 & 0b11) as u32) << (channel * 2)); + + unsafe { w.sar1_atten().bits(new_value) } + }); + } + + fn clear_dig_force() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_read_ctrl + .modify(|_, w| w.sar1_dig_force().clear_bit()); + } + + fn set_start_force() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas_start1 + .modify(|_, w| w.meas1_start_force().set_bit()); + } + + fn set_en_pad_force() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas_start1 + .modify(|_, w| w.sar1_en_pad_force().set_bit()); + } + + fn set_en_pad(channel: u8) { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas_start1 + .modify(|_, w| unsafe { w.sar1_en_pad().bits(1 << channel) }); + } + + fn clear_start_sar() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas_start1 + .modify(|_, w| w.meas1_start_sar().clear_bit()); + } + + fn set_start_sar() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas_start1 + .modify(|_, w| w.meas1_start_sar().set_bit()); + } + + fn read_done_sar() -> bool { + let sensors = unsafe { &*SENS::ptr() }; + sensors.sar_meas_start1.read().meas1_done_sar().bit_is_set() + } + + fn read_data_sar() -> u16 { + let sensors = unsafe { &*SENS::ptr() }; + sensors.sar_meas_start1.read().meas1_data_sar().bits() as u16 + } +} + +impl RegisterAccess for ADC2 { + fn set_bit_width(resolution: u8) { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_start_force + .modify(|_, w| unsafe { w.sar2_bit_width().bits(resolution) }); + } + + fn set_sample_bit(resolution: u8) { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_read_ctrl2 + .modify(|_, w| unsafe { w.sar2_sample_bit().bits(resolution) }); + } + + fn set_attenuation(channel: usize, attenuation: u8) { + let sensors = unsafe { &*SENS::ptr() }; + sensors.sar_atten2.modify(|r, w| { + let new_value = (r.bits() & !(0b11 << (channel * 2))) + | (((attenuation as u8 & 0b11) as u32) << (channel * 2)); + + unsafe { w.sar2_atten().bits(new_value) } + }); + } + + fn clear_dig_force() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_read_ctrl2 + .modify(|_, w| w.sar2_dig_force().clear_bit()); + } + + fn set_start_force() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas_start2 + .modify(|_, w| w.meas2_start_force().set_bit()); + } + + fn set_en_pad_force() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas_start2 + .modify(|_, w| w.sar2_en_pad_force().set_bit()); + } + + fn set_en_pad(channel: u8) { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas_start2 + .modify(|_, w| unsafe { w.sar2_en_pad().bits(1 << channel) }); + } + + fn clear_start_sar() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas_start2 + .modify(|_, w| w.meas2_start_sar().clear_bit()); + } + + fn set_start_sar() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas_start2 + .modify(|_, w| w.meas2_start_sar().set_bit()); + } + + fn read_done_sar() -> bool { + let sensors = unsafe { &*SENS::ptr() }; + sensors.sar_meas_start2.read().meas2_done_sar().bit_is_set() + } + + fn read_data_sar() -> u16 { + let sensors = unsafe { &*SENS::ptr() }; + sensors.sar_meas_start2.read().meas2_data_sar().bits() as u16 + } +} + +pub struct ADC { + adc: PhantomData, + attenuations: [Option; 10], + active_channel: Option, +} + +impl ADC +where + ADCI: RegisterAccess, +{ + pub fn adc(_adc_instance: ADCI, config: AdcConfig) -> Result { + let sensors = unsafe { &*SENS::ptr() }; + + // Set reading and sampling resolution + let resolution: u8 = config.resolution as u8; + + ADCI::set_bit_width(resolution); + ADCI::set_sample_bit(resolution); + + // Set attenuation for pins + let attenuations = config.attenuations; + + for channel in 0..attenuations.len() { + if let Some(attenuation) = attenuations[channel] { + ADC1::set_attenuation(channel, attenuation as u8); + } + } + + // Set controller to RTC + ADCI::clear_dig_force(); + ADCI::set_start_force(); + ADCI::set_en_pad_force(); + sensors + .sar_touch_ctrl1 + .modify(|_, w| w.xpd_hall_force().set_bit()); + sensors + .sar_touch_ctrl1 + .modify(|_, w| w.hall_phase_force().set_bit()); + + // Set power to SW power on + sensors + .sar_meas_wait2 + .modify(|_, w| unsafe { w.force_xpd_sar().bits(0b11) }); + + // disable AMP + sensors + .sar_meas_wait2 + .modify(|_, w| unsafe { w.force_xpd_amp().bits(0b10) }); + sensors + .sar_meas_ctrl + .modify(|_, w| unsafe { w.amp_rst_fb_fsm().bits(0) }); + sensors + .sar_meas_ctrl + .modify(|_, w| unsafe { w.amp_short_ref_fsm().bits(0) }); + sensors + .sar_meas_ctrl + .modify(|_, w| unsafe { w.amp_short_ref_gnd_fsm().bits(0) }); + sensors + .sar_meas_wait1 + .modify(|_, w| unsafe { w.sar_amp_wait1().bits(1) }); + sensors + .sar_meas_wait1 + .modify(|_, w| unsafe { w.sar_amp_wait2().bits(1) }); + sensors + .sar_meas_wait2 + .modify(|_, w| unsafe { w.sar_amp_wait3().bits(1) }); + + let adc = ADC { + adc: PhantomData, + attenuations: config.attenuations, + active_channel: None, + }; + + Ok(adc) + } +} + +impl ADC { + pub fn enable_hall_sensor() { + // Connect hall sensor + let rtcio = unsafe { &*RTCIO::ptr() }; + rtcio.hall_sens.modify(|_, w| w.xpd_hall().set_bit()); + } + + pub fn disable_hall_sensor() { + // Disconnect hall sensor + let rtcio = unsafe { &*RTCIO::ptr() }; + rtcio.hall_sens.modify(|_, w| w.xpd_hall().clear_bit()); + } +} + +impl OneShot for ADC +where + WORD: From, + PIN: Channel, + ADCI: RegisterAccess, +{ + type Error = (); + + fn read(&mut self, _pin: &mut PIN) -> nb::Result { + if self.attenuations[PIN::channel() as usize] == None { + panic!("Channel {} is not configured reading!", PIN::channel()); + } + + if let Some(active_channel) = self.active_channel { + // There is conversion in progress: + // - if it's for a different channel try again later + // - if it's for the given channel, go ahaid and check progress + if active_channel != PIN::channel() { + return Err(nb::Error::WouldBlock); + } + } else { + // If no conversions are in progress, start a new one for given channel + self.active_channel = Some(PIN::channel()); + + ADCI::set_en_pad(PIN::channel() as u8); + + ADCI::clear_start_sar(); + ADCI::set_start_sar(); + } + + // Wait for ADC to finish conversion + let conversion_finished = ADCI::read_done_sar(); + if !conversion_finished { + return Err(nb::Error::WouldBlock); + } + + // Get converted value + let converted_value = ADCI::read_data_sar(); + + // Mark that no conversions are currently in progress + self.active_channel = None; + + Ok(converted_value.into()) + } +} + +#[macro_export] +macro_rules! impl_adc_interface { + ($adc:ident [ + $( ($pin:ident, $channel:expr) ,)+ + ]) => { + + $( + impl Channel<$adc> for $pin { + type ID = u8; + + fn channel() -> u8 { $channel } + } + )+ + } +} + +pub use impl_adc_interface; diff --git a/esp-hal-common/src/analog/adc/esp32c3.rs b/esp-hal-common/src/analog/adc/esp32c3.rs new file mode 100644 index 000000000..8cf7e7c44 --- /dev/null +++ b/esp-hal-common/src/analog/adc/esp32c3.rs @@ -0,0 +1 @@ +// Currently we are missing the SENS peripheral from the SVD diff --git a/esp-hal-common/src/analog/adc/esp32s2.rs b/esp-hal-common/src/analog/adc/esp32s2.rs new file mode 100644 index 000000000..67ec24d8d --- /dev/null +++ b/esp-hal-common/src/analog/adc/esp32s2.rs @@ -0,0 +1,379 @@ +use core::marker::PhantomData; + +use embedded_hal::adc::{Channel, OneShot}; +use esp32s2_pac::APB_SARADC; + +use crate::{ + analog::{ADC1, ADC2}, + pac::SENS, +}; + +/// The sampling/readout resolution of the ADC +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum Resolution { + Resolution13Bit, +} + +/// The attenuation of the ADC pin +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum Attenuation { + Attenuation0dB = 0b00, + Attenuation2p5dB = 0b01, + Attenuation6dB = 0b10, + Attenuation11dB = 0b11, +} + +pub struct AdcConfig { + pub resolution: Resolution, + pub attenuations: [Option; 10], + _phantom: PhantomData, +} + +impl AdcConfig +where + ADCI: RegisterAccess, +{ + pub fn new() -> AdcConfig { + Self::default() + } + + pub fn enable_pin>( + &mut self, + _pin: &PIN, + attenuation: Attenuation, + ) { + self.attenuations[PIN::channel() as usize] = Some(attenuation); + } +} + +impl Default for AdcConfig { + fn default() -> Self { + AdcConfig { + resolution: Resolution::Resolution13Bit, + attenuations: [None; 10], + _phantom: PhantomData::default(), + } + } +} + +pub trait RegisterAccess { + fn set_bit_width(resolution: u8); + + fn set_sample_bit(resolution: u8); + + fn set_attenuation(channel: usize, attenuation: u8); + + fn clear_dig_force(); + + fn set_start_force(); + + fn set_en_pad_force(); + + fn set_en_pad(channel: u8); + + fn clear_start_sar(); + + fn set_start_sar(); + + fn read_done_sar() -> bool; + + fn read_data_sar() -> u16; +} + +impl RegisterAccess for ADC1 { + fn set_bit_width(_resolution: u8) { + // no-op + } + + fn set_sample_bit(_resolution: u8) { + // no-op + } + + fn set_attenuation(channel: usize, attenuation: u8) { + let sensors = unsafe { &*SENS::ptr() }; + sensors.sar_atten1.modify(|r, w| { + let new_value = (r.bits() & !(0b11 << (channel * 2))) + | (((attenuation as u8 & 0b11) as u32) << (channel * 2)); + + unsafe { w.sar1_atten().bits(new_value) } + }); + } + + fn clear_dig_force() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas1_mux + .modify(|_, w| w.sar1_dig_force().clear_bit()); + } + + fn set_start_force() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas1_ctrl2 + .modify(|_, w| w.meas1_start_force().set_bit()); + } + + fn set_en_pad_force() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas1_ctrl2 + .modify(|_, w| w.sar1_en_pad_force().set_bit()); + } + + fn set_en_pad(channel: u8) { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas1_ctrl2 + .modify(|_, w| unsafe { w.sar1_en_pad().bits(1 << channel) }); + } + + fn clear_start_sar() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas1_ctrl2 + .modify(|_, w| w.meas1_start_sar().clear_bit()); + } + + fn set_start_sar() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas1_ctrl2 + .modify(|_, w| w.meas1_start_sar().set_bit()); + } + + fn read_done_sar() -> bool { + let sensors = unsafe { &*SENS::ptr() }; + sensors.sar_meas1_ctrl2.read().meas1_done_sar().bit_is_set() + } + + fn read_data_sar() -> u16 { + let sensors = unsafe { &*SENS::ptr() }; + sensors.sar_meas1_ctrl2.read().meas1_data_sar().bits() as u16 + } +} + +impl RegisterAccess for ADC2 { + fn set_bit_width(_resolution: u8) { + // no-op + } + + fn set_sample_bit(_resolution: u8) { + // no-op + } + + fn set_attenuation(channel: usize, attenuation: u8) { + let sensors = unsafe { &*SENS::ptr() }; + sensors.sar_atten2.modify(|r, w| { + let new_value = (r.bits() & !(0b11 << (channel * 2))) + | (((attenuation as u8 & 0b11) as u32) << (channel * 2)); + + unsafe { w.sar2_atten().bits(new_value) } + }); + } + + fn clear_dig_force() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas2_mux + .modify(|_, w| w.sar2_rtc_force().set_bit()); + + let sar_apb = unsafe { &*APB_SARADC::ptr() }; + sar_apb + .arb_ctrl + .modify(|_, w| w.adc_arb_rtc_force().set_bit()); + } + + fn set_start_force() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas2_ctrl2 + .modify(|_, w| w.meas2_start_force().set_bit()); + } + + fn set_en_pad_force() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas2_ctrl2 + .modify(|_, w| w.sar2_en_pad_force().set_bit()); + } + + fn set_en_pad(channel: u8) { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas2_ctrl2 + .modify(|_, w| unsafe { w.sar2_en_pad().bits(1 << channel) }); + } + + fn clear_start_sar() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas2_ctrl2 + .modify(|_, w| w.meas2_start_sar().clear_bit()); + } + + fn set_start_sar() { + let sensors = unsafe { &*SENS::ptr() }; + sensors + .sar_meas2_ctrl2 + .modify(|_, w| w.meas2_start_sar().set_bit()); + } + + fn read_done_sar() -> bool { + let sensors = unsafe { &*SENS::ptr() }; + sensors.sar_meas2_ctrl2.read().meas2_done_sar().bit_is_set() + } + + fn read_data_sar() -> u16 { + let sensors = unsafe { &*SENS::ptr() }; + sensors.sar_meas2_ctrl2.read().meas2_data_sar().bits() as u16 + } +} + +pub struct ADC { + adc: PhantomData, + attenuations: [Option; 10], + active_channel: Option, +} + +impl ADC +where + ADCI: RegisterAccess, +{ + pub fn adc(_adc_instance: ADCI, config: AdcConfig) -> Result { + let sensors = unsafe { &*SENS::ptr() }; + + // Set reading and sampling resolution + let resolution: u8 = config.resolution as u8; + + ADCI::set_bit_width(resolution); + ADCI::set_sample_bit(resolution); + + // Set attenuation for pins + let attenuations = config.attenuations; + + for channel in 0..attenuations.len() { + if let Some(attenuation) = attenuations[channel] { + ADC1::set_attenuation(channel, attenuation as u8); + } + } + + // Set controller to RTC + ADCI::clear_dig_force(); + ADCI::set_start_force(); + ADCI::set_en_pad_force(); + sensors + .sar_hall_ctrl + .modify(|_, w| w.xpd_hall_force().set_bit()); + sensors + .sar_hall_ctrl + .modify(|_, w| w.hall_phase_force().set_bit()); + + // Set power to SW power on + sensors + .sar_meas1_ctrl1 + .modify(|_, w| w.rtc_saradc_clkgate_en().set_bit()); + + sensors + .sar_power_xpd_sar + .modify(|_, w| w.sarclk_en().set_bit()); + + sensors + .sar_power_xpd_sar + .modify(|_, w| unsafe { w.force_xpd_sar().bits(0b11) }); + + // disable AMP + sensors + .sar_meas1_ctrl1 + .modify(|_, w| unsafe { w.force_xpd_amp().bits(0b11) }); + sensors + .sar_amp_ctrl3 + .modify(|_, w| unsafe { w.amp_rst_fb_fsm().bits(0) }); + sensors + .sar_amp_ctrl3 + .modify(|_, w| unsafe { w.amp_short_ref_fsm().bits(0) }); + sensors + .sar_amp_ctrl3 + .modify(|_, w| unsafe { w.amp_short_ref_gnd_fsm().bits(0) }); + sensors + .sar_amp_ctrl1 + .modify(|_, w| unsafe { w.sar_amp_wait1().bits(1) }); + sensors + .sar_amp_ctrl1 + .modify(|_, w| unsafe { w.sar_amp_wait2().bits(1) }); + sensors + .sar_amp_ctrl2 + .modify(|_, w| unsafe { w.sar_amp_wait3().bits(1) }); + + let adc = ADC { + adc: PhantomData, + attenuations: config.attenuations, + active_channel: None, + }; + + Ok(adc) + } +} + +impl OneShot for ADC +where + WORD: From, + PIN: Channel, + ADCI: RegisterAccess, +{ + type Error = (); + + fn read(&mut self, _pin: &mut PIN) -> nb::Result { + if self.attenuations[PIN::channel() as usize] == None { + panic!("Channel {} is not configured reading!", PIN::channel()); + } + + if let Some(active_channel) = self.active_channel { + // There is conversion in progress: + // - if it's for a different channel try again later + // - if it's for the given channel, go ahaid and check progress + if active_channel != PIN::channel() { + return Err(nb::Error::WouldBlock); + } + } else { + // If no conversions are in progress, start a new one for given channel + self.active_channel = Some(PIN::channel()); + + ADCI::set_en_pad(PIN::channel() as u8); + + ADCI::clear_start_sar(); + ADCI::set_start_sar(); + } + + // Wait for ADC to finish conversion + let conversion_finished = ADCI::read_done_sar(); + if !conversion_finished { + return Err(nb::Error::WouldBlock); + } + + // Get converted value + let converted_value = ADCI::read_data_sar(); + + // Mark that no conversions are currently in progress + self.active_channel = None; + + Ok(converted_value.into()) + } +} + +#[macro_export] +macro_rules! impl_adc_interface { + ($adc:ident [ + $( ($pin:ident, $channel:expr) ,)+ + ]) => { + + $( + impl Channel<$adc> for $pin { + type ID = u8; + + fn channel() -> u8 { $channel } + } + )+ + } +} + +pub use impl_adc_interface; diff --git a/esp-hal-common/src/analog/adc/esp32s3.rs b/esp-hal-common/src/analog/adc/esp32s3.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/esp-hal-common/src/analog/adc/esp32s3.rs @@ -0,0 +1 @@ + diff --git a/esp-hal-common/src/analog/mod.rs b/esp-hal-common/src/analog/mod.rs index 3ba5beab4..6d03e780c 100644 --- a/esp-hal-common/src/analog/mod.rs +++ b/esp-hal-common/src/analog/mod.rs @@ -1,3 +1,8 @@ +#[cfg_attr(feature = "esp32", path = "adc/esp32.rs")] +#[cfg_attr(feature = "esp32s2", path = "adc/esp32s2.rs")] +#[cfg_attr(feature = "esp32s3", path = "adc/esp32s3.rs")] +#[cfg_attr(feature = "esp32c3", path = "adc/esp32c3.rs")] +pub mod adc; #[cfg(not(any(feature = "esp32c3", feature = "esp32s3")))] pub mod dac; diff --git a/esp-hal-common/src/gpio.rs b/esp-hal-common/src/gpio.rs index 378818acd..ec4a7678b 100644 --- a/esp-hal-common/src/gpio.rs +++ b/esp-hal-common/src/gpio.rs @@ -1159,11 +1159,11 @@ pub fn enable_iomux_clk_gate() { #[doc(hidden)] #[macro_export] macro_rules! analog { - ([ - $($pxi:ident: ($pin_num:expr, $pin_reg:ident, $hold: ident, $mux_sel:ident, + ( + $($pxi:ident: ($pin_num:expr, $pin_reg:expr, $hold: ident, $mux_sel:ident, $fun_sel:ident, $fun_ie:ident, $slp_ie:ident, $slp_sel:ident $(, $rue:ident, $rde:ident, $drv:ident, $slp_oe:ident)?),)+ - ]) => { + ) => { $( impl $pxi { pub fn into_analog(mut self) -> $pxi { @@ -1174,33 +1174,36 @@ macro_rules! analog { $crate::gpio::enable_iomux_clk_gate(); // disable input - rtcio.$pin_reg.modify(|_,w| w.$fun_ie().bit(false)); + paste! { + rtcio.$pin_reg.modify(|_,w| w.$fun_ie().bit(false)); + } // disable output rtcio.enable_w1tc.write(|w| unsafe { w.enable_w1tc().bits(1 << $pin_num) }); - // ESP32-S2 rtcio.rtc_gpio_enable_w1tc.write(|w| unsafe { w.reg_rtcio_reg_gpio_enable_w1tc().bits(1 << $pin_num) }); - //rtcio.rtc_gpio_enable_w1tc.write(|w| unsafe { w.rtc_gpio_enable_w1tc().bits(1 << $pin_num) }); // disable open drain rtcio.pin[$pin_num].modify(|_,w| w.pin_pad_driver().bit(false)); - //rtcio.rtc_gpio_pin[$pin_num].modify(|_,w| w.gpio_pin0_pad_driver().bit(false)); - rtcio.$pin_reg.modify(|_,w| { - w.$fun_ie().clear_bit(); + paste! { + rtcio.$pin_reg.modify(|_,w| { + w.$fun_ie().clear_bit(); - // Connect pin to analog / RTC module instead of standard GPIO - w.$mux_sel().set_bit(); + // Connect pin to analog / RTC module instead of standard GPIO + w.$mux_sel().set_bit(); - // Select function "RTC function 1" (GPIO) for analog use - unsafe { w.$fun_sel().bits(0b00) } - }); + // Select function "RTC function 1" (GPIO) for analog use + unsafe { w.$fun_sel().bits(0b00) } + }); + } // Disable pull-up and pull-down resistors on the pin, if it has them - rtcio.$pin_reg.modify(|_,w| { - w - .$rue().bit(false) - .$rde().bit(false) - }); + paste! { + rtcio.$pin_reg.modify(|_,w| { + w + .$rue().bit(false) + .$rde().bit(false) + }); + } )? $pxi { _mode: PhantomData } diff --git a/esp32-hal/.vscode/settings.json b/esp32-hal/.vscode/settings.json index e0839ba9d..54dd8e232 100644 --- a/esp32-hal/.vscode/settings.json +++ b/esp32-hal/.vscode/settings.json @@ -1,7 +1,7 @@ { "rust-analyzer.cargo.features": [], "rust-analyzer.cargo.allFeatures": false, - "editor.formatOnSave": true, + "editor.formatOnSave": false, "rust-analyzer.checkOnSave.allTargets": false, "rust-analyzer.checkOnSave.allFeatures": false, "rust-analyzer.checkOnSave.overrideCommand": [ diff --git a/esp32-hal/Cargo.toml b/esp32-hal/Cargo.toml index 272169dda..5bf89e866 100644 --- a/esp32-hal/Cargo.toml +++ b/esp32-hal/Cargo.toml @@ -29,6 +29,7 @@ embedded-hal = { version = "0.2", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.8" } xtensa-lx = { version = "0.7", features = ["esp32"] } xtensa-lx-rt = { version = "0.12", features = ["esp32"], optional = true } +nb = "1.0.0" [dependencies.esp-hal-common] path = "../esp-hal-common" diff --git a/esp32-hal/examples/adc.rs b/esp32-hal/examples/adc.rs new file mode 100644 index 000000000..c6ef637c1 --- /dev/null +++ b/esp32-hal/examples/adc.rs @@ -0,0 +1,55 @@ +//! Connect a potentiometer to PIN25 and see the read values change when +//! rotating the shaft. If could also connect the PIN to GND or 3V3 to see the +//! maximum and minimum raw values read. + +#![no_std] +#![no_main] + +use esp32_hal::{ + clock::ClockControl, + gpio::IO, + pac::Peripherals, + prelude::*, + AdcConfig, + Attenuation, + Delay, + RtcCntl, + Timer, + ADC, + ADC2, +}; +use esp_println::println; +use panic_halt as _; +use xtensa_lx_rt::entry; + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take().unwrap(); + let system = peripherals.DPORT.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + let mut timer0 = Timer::new(peripherals.TIMG0, clocks.apb_clock); + let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL); + + // Disable MWDT and RWDT (Watchdog) flash boot protection + timer0.disable(); + rtc_cntl.set_wdt_global_enable(false); + + let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + let mut pin25 = io.pins.gpio25.into_analog(); + + // Create ADC instances + let analog = peripherals.SENS.split(); + + let mut adc2_config = AdcConfig::new(); + adc2_config.enable_pin(&pin25, Attenuation::Attenuation11dB); + let mut adc2 = ADC::::adc(analog.adc2, adc2_config).unwrap(); + + let mut delay = Delay::new(&clocks); + + loop { + let pin25_value: u16 = nb::block!(adc2.read(&mut pin25)).unwrap(); + println!("PIN25 ADC reading = {}", pin25_value); + delay.delay_ms(1500u32); + } +} diff --git a/esp32-hal/src/adc.rs b/esp32-hal/src/adc.rs new file mode 100644 index 000000000..5ff656905 --- /dev/null +++ b/esp32-hal/src/adc.rs @@ -0,0 +1,52 @@ +//! Analog to digital (ADC) conversion support. +//! +//! This module provides functions for reading analog values from two +//! analog to digital converters available on the ESP32: `ADC1` and `ADC2`. +//! +//! The following pins can be configured for analog readout: +//! +//! | Channel | ADC1 | ADC2 | +//! |---------|----------------------|---------------| +//! | 0 | GPIO36 (SENSOR_VP) | GPIO4 | +//! | 1 | GPIO37 (SENSOR_CAPP) | GPIO0 | +//! | 2 | GPIO38 (SENSOR_CAPN) | GPIO2 | +//! | 3 | GPIO39 (SENSOR_VN) | GPIO15 (MTDO) | +//! | 4 | GPIO33 (32K_XP) | GPIO13 (MTCK) | +//! | 5 | GPIO32 (32K_XN) | GPIO12 (MTDI) | +//! | 6 | GPIO34 (VDET_1) | GPIO14 (MTMS) | +//! | 7 | GPIO35 (VDET_2) | GPIO27 | +//! | 8 | | GPIO25 | +//! | 9 | | GPIO26 | + +use embedded_hal::adc::Channel; +use esp_hal_common::analog::{adc::impl_adc_interface, ADC1, ADC2}; + +use crate::{gpio::*, gpio_types::Analog}; + +impl_adc_interface! { + ADC1 [ + (Gpio36, 0), // Alt. name: SENSOR_VP + (Gpio37, 1), // Alt. name: SENSOR_CAPP + (Gpio38, 2), // Alt. name: SENSOR_CAPN + (Gpio39, 3), // Alt. name: SENSOR_VN + (Gpio33, 4), // Alt. name: 32K_XP + (Gpio32, 5), // Alt. name: 32K_XN + (Gpio34, 6), // Alt. name: VDET_1 + (Gpio35, 7), // Alt. name: VDET_2 + ] +} + +impl_adc_interface! { + ADC2 [ + (Gpio4, 0), + (Gpio0, 1), + (Gpio2, 2), + (Gpio15, 3), // Alt. name: MTDO + (Gpio13, 4), // Alt. name: MTCK + (Gpio12, 5), // Alt. name: MTDI + (Gpio14, 6), // Alt. name: MTMS + (Gpio27, 7), + (Gpio25, 8), + (Gpio26, 9), + ] +} diff --git a/esp32-hal/src/gpio.rs b/esp32-hal/src/gpio.rs index 6a04fa96a..8e47fe68a 100644 --- a/esp32-hal/src/gpio.rs +++ b/esp32-hal/src/gpio.rs @@ -54,7 +54,7 @@ gpio! { Gpio39: (gpio39, 39, gpio39, Input, 0, Bank1, None), } -analog! {[ +analog! { Gpio36: (0, sensor_pads, sense1_hold, sense1_mux_sel, sense1_fun_sel, sense1_fun_ie, sense1_slp_ie, sense1_slp_sel ), Gpio37: (1, sensor_pads, sense2_hold, sense2_mux_sel, sense2_fun_sel, sense2_fun_ie, sense2_slp_ie, sense2_slp_sel ), Gpio38: (2, sensor_pads, sense3_hold, sense3_mux_sel, sense3_fun_sel, sense3_fun_ie, sense3_slp_ie, sense3_slp_sel ), @@ -73,4 +73,4 @@ analog! {[ Gpio12: (15, touch_pad5, hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), Gpio14: (16, touch_pad6, hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), Gpio27: (17, touch_pad7, hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), -]} +} diff --git a/esp32-hal/src/lib.rs b/esp32-hal/src/lib.rs index 73a9ebdbf..719804f42 100644 --- a/esp32-hal/src/lib.rs +++ b/esp32-hal/src/lib.rs @@ -2,6 +2,7 @@ pub use embedded_hal as ehal; pub use esp_hal_common::{ + analog::{adc::*, *}, clock, cpu_control::CpuControl, efuse, @@ -25,6 +26,7 @@ pub use esp_hal_common::{ pub use self::gpio::IO; +pub mod adc; pub mod dac; pub mod gpio; diff --git a/esp32s2-hal/Cargo.toml b/esp32s2-hal/Cargo.toml index 860e657df..0ff7be04c 100644 --- a/esp32s2-hal/Cargo.toml +++ b/esp32s2-hal/Cargo.toml @@ -39,6 +39,7 @@ embedded-graphics = "0.7" panic-halt = "0.2" ssd1306 = "0.7" smart-leds = "0.3" +esp-println = { version = "0.1.0", features = ["esp32s2"] } [features] default = ["rt"] diff --git a/esp32s2-hal/examples/adc.rs b/esp32s2-hal/examples/adc.rs new file mode 100644 index 000000000..8bc2b2a44 --- /dev/null +++ b/esp32s2-hal/examples/adc.rs @@ -0,0 +1,58 @@ +//! Connect a potentiometer to PIN3 and see the read values change when +//! rotating the shaft. If could also connect the PIN to GND or 3V3 to see the +//! maximum and minimum raw values read. +//! +//! THIS CURRENTLY DOESN'T WORK IN DEBUG BUILDS! THIS NEEDS TO GET FIGURED OUT! + +#![no_std] +#![no_main] + +use esp32s2_hal::{ + clock::ClockControl, + gpio::IO, + pac::Peripherals, + prelude::*, + AdcConfig, + Attenuation, + Delay, + RtcCntl, + Timer, + ADC, + ADC1, +}; +use esp_println::println; +use panic_halt as _; +use xtensa_lx_rt::entry; + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take().unwrap(); + let system = peripherals.SYSTEM.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + let mut timer0 = Timer::new(peripherals.TIMG0, clocks.apb_clock); + let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL); + + // Disable MWDT and RWDT (Watchdog) flash boot protection + timer0.disable(); + rtc_cntl.set_wdt_global_enable(false); + + let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + let mut pin3 = io.pins.gpio3.into_analog(); + + // Create ADC instances + let analog = peripherals.SENS.split(); + + let mut adc1_config = AdcConfig::new(); + adc1_config.enable_pin(&pin3, Attenuation::Attenuation11dB); + let mut adc1 = ADC::::adc(analog.adc1, adc1_config).unwrap(); + + let mut delay = Delay::new(&clocks); + + loop { + println!("About to read from ADC"); + let pin3_value: u16 = nb::block!(adc1.read(&mut pin3)).unwrap(); + println!("PIN3 ADC reading = {}", pin3_value); + delay.delay_ms(1500u32); + } +} diff --git a/esp32s2-hal/src/adc.rs b/esp32s2-hal/src/adc.rs new file mode 100644 index 000000000..6d04189e4 --- /dev/null +++ b/esp32s2-hal/src/adc.rs @@ -0,0 +1,34 @@ +use embedded_hal::adc::Channel; +use esp_hal_common::analog::{adc::impl_adc_interface, ADC1, ADC2}; + +use crate::{gpio::*, gpio_types::Analog}; + +impl_adc_interface! { + ADC1 [ + (Gpio1, 0), + (Gpio2, 1), + (Gpio3, 2), + (Gpio4, 3), + (Gpio5, 4), + (Gpio6, 5), + (Gpio7, 6), + (Gpio8, 7), + (Gpio9, 8), + (Gpio10,9), + ] +} + +impl_adc_interface! { + ADC2 [ + (Gpio11, 0), + (Gpio12, 1), + (Gpio13, 2), + (Gpio14, 3), + (Gpio15, 4), + (Gpio16, 5), + (Gpio17, 6), + (Gpio18, 7), + (Gpio19, 8), + (Gpio20, 9), + ] +} diff --git a/esp32s2-hal/src/gpio.rs b/esp32s2-hal/src/gpio.rs index c7b38512f..b6d2de35c 100644 --- a/esp32s2-hal/src/gpio.rs +++ b/esp32s2-hal/src/gpio.rs @@ -59,8 +59,27 @@ gpio! { Gpio46: (gpio46, 46, gpio46, IO,Input, Bank1, None), } -// TODO other analog capable gpios - see https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s2/rtc_io_periph.c -analog! {[ - Gpio17: (17, pad_dac1, pdac1_hold, pdac1_mux_sel, pdac1_fun_sel, pdac1_fun_ie, pdac1_slp_ie, pdac1_slp_sel, pdac1_rue, pdac1_rde, pdac1_drv, pdac1_slp_oe), - Gpio18: (18, pad_dac2, pdac2_hold, pdac2_mux_sel, pdac2_fun_sel, pdac2_fun_ie, pdac2_slp_ie, pdac2_slp_sel, pdac2_rue, pdac2_rde, pdac2_drv, pdac2_slp_oe), -]} +analog! { + Gpio0: ( 0, touch_pad[0], touch_pad0_hold, touch_pad0_mux_sel, touch_pad0_fun_sel, touch_pad0_fun_ie, touch_pad0_slp_ie, touch_pad0_slp_sel, touch_pad0_rue, touch_pad0_rde, touch_pad0_drv, touch_pad0_slp_oe), + Gpio1: ( 1, touch_pad[1], touch_pad1_hold, touch_pad0_mux_sel, touch_pad0_fun_sel, touch_pad0_fun_ie, touch_pad0_slp_ie, touch_pad0_slp_sel, touch_pad0_rue, touch_pad0_rde, touch_pad0_drv, touch_pad0_slp_oe), + Gpio2: ( 2, touch_pad[2], touch_pad2_hold, touch_pad0_mux_sel, touch_pad0_fun_sel, touch_pad0_fun_ie, touch_pad0_slp_ie, touch_pad0_slp_sel, touch_pad0_rue, touch_pad0_rde, touch_pad0_drv, touch_pad0_slp_oe), + Gpio3: ( 3, touch_pad[3], touch_pad3_hold, touch_pad0_mux_sel, touch_pad0_fun_sel, touch_pad0_fun_ie, touch_pad0_slp_ie, touch_pad0_slp_sel, touch_pad0_rue, touch_pad0_rde, touch_pad0_drv, touch_pad0_slp_oe), + Gpio4: ( 4, touch_pad[4], touch_pad4_hold, touch_pad0_mux_sel, touch_pad0_fun_sel, touch_pad0_fun_ie, touch_pad0_slp_ie, touch_pad0_slp_sel, touch_pad0_rue, touch_pad0_rde, touch_pad0_drv, touch_pad0_slp_oe), + Gpio5: ( 5, touch_pad[5], touch_pad5_hold, touch_pad0_mux_sel, touch_pad0_fun_sel, touch_pad0_fun_ie, touch_pad0_slp_ie, touch_pad0_slp_sel, touch_pad0_rue, touch_pad0_rde, touch_pad0_drv, touch_pad0_slp_oe), + Gpio6: ( 6, touch_pad[6], touch_pad6_hold, touch_pad0_mux_sel, touch_pad0_fun_sel, touch_pad0_fun_ie, touch_pad0_slp_ie, touch_pad0_slp_sel, touch_pad0_rue, touch_pad0_rde, touch_pad0_drv, touch_pad0_slp_oe), + Gpio7: ( 7, touch_pad[7], touch_pad7_hold, touch_pad0_mux_sel, touch_pad0_fun_sel, touch_pad0_fun_ie, touch_pad0_slp_ie, touch_pad0_slp_sel, touch_pad0_rue, touch_pad0_rde, touch_pad0_drv, touch_pad0_slp_oe), + Gpio8: ( 8, touch_pad[8], touch_pad8_hold, touch_pad0_mux_sel, touch_pad0_fun_sel, touch_pad0_fun_ie, touch_pad0_slp_ie, touch_pad0_slp_sel, touch_pad0_rue, touch_pad0_rde, touch_pad0_drv, touch_pad0_slp_oe), + Gpio9: ( 9, touch_pad[9], touch_pad9_hold, touch_pad0_mux_sel, touch_pad0_fun_sel, touch_pad0_fun_ie, touch_pad0_slp_ie, touch_pad0_slp_sel, touch_pad0_rue, touch_pad0_rde, touch_pad0_drv, touch_pad0_slp_oe), + Gpio10: (10, touch_pad[10], touch_pad10_hold, touch_pad0_mux_sel, touch_pad0_fun_sel, touch_pad0_fun_ie, touch_pad0_slp_ie, touch_pad0_slp_sel, touch_pad0_rue, touch_pad0_rde, touch_pad0_drv, touch_pad0_slp_oe), + Gpio11: (11, touch_pad[11], touch_pad11_hold, touch_pad0_mux_sel, touch_pad0_fun_sel, touch_pad0_fun_ie, touch_pad0_slp_ie, touch_pad0_slp_sel, touch_pad0_rue, touch_pad0_rde, touch_pad0_drv, touch_pad0_slp_oe), + Gpio12: (12, touch_pad[12], touch_pad12_hold, touch_pad0_mux_sel, touch_pad0_fun_sel, touch_pad0_fun_ie, touch_pad0_slp_ie, touch_pad0_slp_sel, touch_pad0_rue, touch_pad0_rde, touch_pad0_drv, touch_pad0_slp_oe), + Gpio13: (13, touch_pad[13], touch_pad13_hold, touch_pad0_mux_sel, touch_pad0_fun_sel, touch_pad0_fun_ie, touch_pad0_slp_ie, touch_pad0_slp_sel, touch_pad0_rue, touch_pad0_rde, touch_pad0_drv, touch_pad0_slp_oe), + Gpio14: (14, touch_pad[14], touch_pad14_hold, touch_pad0_mux_sel, touch_pad0_fun_sel, touch_pad0_fun_ie, touch_pad0_slp_ie, touch_pad0_slp_sel, touch_pad0_rue, touch_pad0_rde, touch_pad0_drv, touch_pad0_slp_oe), + Gpio15: (15, xtal_32p_pad, x32p_hold, x32p_mux_sel, x32p_fun_sel, x32p_fun_ie, x32p_slp_ie, x32p_slp_sel, x32p_rue, x32p_rde, x32p_drv, x32p_slp_oe), + Gpio16: (16, xtal_32n_pad, x32n_hold, x32n_mux_sel, x32n_fun_sel, x32n_fun_ie, x32n_slp_ie, x32n_slp_sel, x32n_rue, x32n_rde, x32n_drv, x32pn_slp_oe), + Gpio17: (17, pad_dac1, pdac1_hold, pdac1_mux_sel, pdac1_fun_sel, pdac1_fun_ie, pdac1_slp_ie, pdac1_slp_sel, pdac1_rue, pdac1_rde, pdac1_drv, pdac1_slp_oe), + Gpio18: (18, pad_dac2, pdac2_hold, pdac2_mux_sel, pdac2_fun_sel, pdac2_fun_ie, pdac2_slp_ie, pdac2_slp_sel, pdac2_rue, pdac2_rde, pdac2_drv, pdac2_slp_oe), + Gpio19: (19, rtc_pad19, rtc_pad19_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio20: (20, rtc_pad20, rtc_pad20_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio21: (21, rtc_pad21, rtc_pad21_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), +} diff --git a/esp32s2-hal/src/lib.rs b/esp32s2-hal/src/lib.rs index 9e79741e6..9dc162a85 100644 --- a/esp32s2-hal/src/lib.rs +++ b/esp32s2-hal/src/lib.rs @@ -2,6 +2,7 @@ pub use embedded_hal as ehal; pub use esp_hal_common::{ + analog::{adc::*, *}, clock, efuse, gpio as gpio_types, @@ -25,6 +26,7 @@ pub use esp_hal_common::{ pub use self::gpio::IO; +pub mod adc; pub mod dac; pub mod gpio; diff --git a/esp32s3-hal/src/gpio.rs b/esp32s3-hal/src/gpio.rs index dc546be75..a7cb1a011 100644 --- a/esp32s3-hal/src/gpio.rs +++ b/esp32s3-hal/src/gpio.rs @@ -64,4 +64,27 @@ gpio! { Gpio48: (gpio48, 48, gpio[48], IO, 0, Bank1, None), } -// TODO add analog capable gpios - see https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s3/rtc_io_periph.c +analog! { + Gpio0: ( 0, touch_pad0, touch_pad0_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio1: ( 1, touch_pad1, touch_pad1_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio2: ( 2, touch_pad2, touch_pad2_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio3: ( 3, touch_pad3, touch_pad3_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio4: ( 4, touch_pad4, touch_pad4_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio5: ( 5, touch_pad5, touch_pad5_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio6: ( 6, touch_pad6, touch_pad6_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio7: ( 7, touch_pad7, touch_pad7_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio8: ( 8, touch_pad8, touch_pad8_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio9: ( 9, touch_pad9, touch_pad9_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio10: (10, touch_pad10, touch_pad10_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio11: (11, touch_pad11, touch_pad11_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio12: (12, touch_pad12, touch_pad12_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio13: (13, touch_pad13, touch_pad13_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio14: (14, touch_pad14, touch_pad14_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio15: (15, xtal_32p_pad, x32p_hold, x32p_mux_sel, x32p_fun_sel, x32p_fun_ie, x32p_slp_ie, x32p_slp_sel, x32p_rue, x32p_rde, x32p_drv, x32p_slp_oe), + Gpio16: (16, xtal_32n_pad, x32n_hold, x32n_mux_sel, x32n_fun_sel, x32n_fun_ie, x32n_slp_ie, x32n_slp_sel, x32n_rue, x32n_rde, x32n_drv, x32pn_slp_oe), + Gpio17: (17, pad_dac1, pdac1_hold, pdac1_mux_sel,pdac1_fun_sel,pdac1_fun_ie, pdac1_slp_ie, pdac1_slp_sel, pdac1_rue, pdac1_rde, pdac1_drv, pdac1_slp_oe), + Gpio18: (18, pad_dac2, pdac2_hold, pdac2_mux_sel,pdac2_fun_sel,pdac2_fun_ie, pdac2_slp_ie, pdac2_slp_sel, pdac2_rue, pdac2_rde, pdac2_drv, pdac2_slp_oe), + Gpio19: (19, rtc_pad19, rtc_pad19_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio20: (20, rtc_pad20, rtc_pad20_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), + Gpio21: (21, rtc_pad21, rtc_pad21_hold, mux_sel, fun_sel, fun_ie, slp_ie, slp_sel, rue, rde, drv, slp_oe), +}