Refactor the analog module (#1100)

* Create virtual peripherals for `ADC`/`DAC`

* Refactor the `analog::dac` module

* Refactor the `analog::adc` module

* Decouple the ADC driver from the `embedded-hal` traits

* Update `CHANGELOG.md`

* Seal the `AdcCalScheme` trait, reduce visibility of `AdcCalEfuse` trait

* Remove `APB_SARADC`/`SENS` peripherals from the `Peripherals` struct
This commit is contained in:
Jesse Braham 2024-01-25 16:46:27 +00:00 committed by GitHub
parent 43f212dc72
commit f52aa1351c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 482 additions and 1034 deletions

View File

@ -23,6 +23,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Removed
### Breaking
- `ADC` and `DAC` drivers now take virtual peripherals in their constructors, instead of splitting `APB_SARADC`/`SENS` (#1100)
- The `DAC` driver's constructor is now `new` instead of `dac`, to be more consistent with other APIs (#1100)
## [0.15.0] - 2024-01-19
### Added

View File

@ -1,6 +1,7 @@
use core::marker::PhantomData;
use crate::adc::{
private,
AdcCalEfuse,
AdcCalScheme,
AdcCalSource,
@ -27,6 +28,8 @@ pub struct AdcCalBasic<ADCI> {
_phantom: PhantomData<ADCI>,
}
impl<ADCI> private::Sealed for AdcCalBasic<ADCI> {}
impl<ADCI> AdcCalScheme<ADCI> for AdcCalBasic<ADCI>
where
ADCI: AdcCalEfuse + CalibrationAccess,

View File

@ -1,6 +1,7 @@
use core::marker::PhantomData;
use crate::adc::{
private,
AdcCalEfuse,
AdcCalLine,
AdcCalScheme,
@ -60,6 +61,8 @@ pub struct AdcCalCurve<ADCI> {
_phantom: PhantomData<ADCI>,
}
impl<ADCI> private::Sealed for AdcCalCurve<ADCI> {}
impl<ADCI> AdcCalScheme<ADCI> for AdcCalCurve<ADCI>
where
ADCI: AdcCalEfuse + AdcHasLineCal + AdcHasCurveCal + CalibrationAccess,
@ -126,17 +129,17 @@ macro_rules! coeff_tables {
mod impls {
use super::*;
impl AdcHasCurveCal for crate::adc::ADC1 {
impl AdcHasCurveCal for crate::peripherals::ADC1 {
const CURVES_COEFFS: CurvesCoeffs = CURVES_COEFFS1;
}
#[cfg(esp32c3)]
impl AdcHasCurveCal for crate::adc::ADC2 {
impl AdcHasCurveCal for crate::peripherals::ADC2 {
const CURVES_COEFFS: CurvesCoeffs = CURVES_COEFFS1;
}
#[cfg(esp32s3)]
impl AdcHasCurveCal for crate::adc::ADC2 {
impl AdcHasCurveCal for crate::peripherals::ADC2 {
const CURVES_COEFFS: CurvesCoeffs = CURVES_COEFFS2;
}

View File

@ -1,6 +1,7 @@
use core::marker::PhantomData;
use crate::adc::{
private,
AdcCalBasic,
AdcCalEfuse,
AdcCalScheme,
@ -48,6 +49,8 @@ pub struct AdcCalLine<ADCI> {
_phantom: PhantomData<ADCI>,
}
impl<ADCI> private::Sealed for AdcCalLine<ADCI> {}
impl<ADCI> AdcCalScheme<ADCI> for AdcCalLine<ADCI>
where
ADCI: AdcCalEfuse + AdcHasLineCal + CalibrationAccess,
@ -96,7 +99,7 @@ where
}
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
impl AdcHasLineCal for crate::adc::ADC1 {}
impl AdcHasLineCal for crate::peripherals::ADC1 {}
#[cfg(any(esp32c3, esp32s3))]
impl AdcHasLineCal for crate::adc::ADC2 {}
impl AdcHasLineCal for crate::peripherals::ADC2 {}

View File

@ -0,0 +1,14 @@
#[cfg(any(esp32c3, esp32c6, esp32s3))]
pub use self::curve::{AdcCalCurve, AdcHasCurveCal};
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
pub use self::{
basic::AdcCalBasic,
line::{AdcCalLine, AdcHasLineCal},
};
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
mod basic;
#[cfg(any(esp32c3, esp32c6, esp32s3))]
mod curve;
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
mod line;

View File

@ -1,14 +1,12 @@
use core::marker::PhantomData;
use embedded_hal::adc::{Channel, OneShot};
pub use crate::analog::{ADC1, ADC2};
use super::{AdcChannel, Attenuation};
use crate::{
peripheral::PeripheralRef,
peripherals::{RTC_IO, SENS},
peripherals::{ADC1, ADC2, RTC_IO, SENS},
};
/// The sampling/readout resolution of the ADC
/// The sampling/readout resolution of the ADC.
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum Resolution {
Resolution9Bit = 0b00,
@ -17,20 +15,16 @@ pub enum Resolution {
Resolution12Bit = 0b11,
}
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum Attenuation {
Attenuation0dB = 0b00,
Attenuation2p5dB = 0b01,
Attenuation6dB = 0b10,
Attenuation11dB = 0b11,
}
/// An I/O pin which can be read using the ADC.
pub struct AdcPin<PIN, ADCI> {
pub pin: PIN,
_phantom: PhantomData<ADCI>,
}
impl<PIN: Channel<ADCI, ID = u8>, ADCI> Channel<ADCI> for AdcPin<PIN, ADCI> {
impl<PIN, ADCI> embedded_hal::adc::Channel<ADCI> for AdcPin<PIN, ADCI>
where
PIN: embedded_hal::adc::Channel<ADCI, ID = u8>,
{
type ID = u8;
fn channel() -> Self::ID {
@ -38,6 +32,7 @@ impl<PIN: Channel<ADCI, ID = u8>, ADCI> Channel<ADCI> for AdcPin<PIN, ADCI> {
}
}
/// Configuration for the ADC.
pub struct AdcConfig<ADCI> {
pub resolution: Resolution,
pub attenuations: [Option<Attenuation>; 10],
@ -49,16 +44,14 @@ where
ADCI: RegisterAccess,
{
pub fn new() -> AdcConfig<ADCI> {
crate::into_ref!();
Self::default()
}
pub fn enable_pin<PIN: Channel<ADCI, ID = u8>>(
&mut self,
pin: PIN,
attenuation: Attenuation,
) -> AdcPin<PIN, ADCI> {
self.attenuations[PIN::channel() as usize] = Some(attenuation);
pub fn enable_pin<PIN>(&mut self, pin: PIN, attenuation: Attenuation) -> AdcPin<PIN, ADCI>
where
PIN: AdcChannel,
{
self.attenuations[PIN::CHANNEL as usize] = Some(attenuation);
AdcPin {
pin,
@ -77,6 +70,7 @@ impl<ADCI> Default for AdcConfig<ADCI> {
}
}
#[doc(hidden)]
pub trait RegisterAccess {
fn set_bit_width(resolution: u8);
@ -101,25 +95,21 @@ pub trait RegisterAccess {
fn read_data_sar() -> u16;
}
#[doc(hidden)]
impl RegisterAccess for ADC1 {
fn set_bit_width(resolution: u8) {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.sar_start_force()
.modify(|_, w| unsafe { w.sar1_bit_width().bits(resolution) });
}
fn set_sample_bit(resolution: u8) {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.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| {
unsafe { &*SENS::ptr() }.sar_atten1().modify(|r, w| {
let new_value = (r.bits() & !(0b11 << (channel * 2)))
| (((attenuation as u8 & 0b11) as u32) << (channel * 2));
@ -128,50 +118,43 @@ impl RegisterAccess for ADC1 {
}
fn clear_dig_force() {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.sar_read_ctrl()
.modify(|_, w| w.sar1_dig_force().clear_bit());
}
fn set_start_force() {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.sar_meas_start1()
.modify(|_, w| w.meas1_start_force().set_bit());
}
fn set_en_pad_force() {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.sar_meas_start1()
.modify(|_, w| w.sar1_en_pad_force().set_bit());
}
fn set_en_pad(channel: u8) {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.sar_meas_start1()
.modify(|_, w| unsafe { w.sar1_en_pad().bits(1 << channel) });
}
fn clear_start_sar() {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.sar_meas_start1()
.modify(|_, w| w.meas1_start_sar().clear_bit());
}
fn set_start_sar() {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.sar_meas_start1()
.modify(|_, w| w.meas1_start_sar().set_bit());
}
fn read_done_sar() -> bool {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.sar_meas_start1()
.read()
.meas1_done_sar()
@ -179,29 +162,29 @@ impl RegisterAccess for ADC1 {
}
fn read_data_sar() -> u16 {
let sensors = unsafe { &*SENS::ptr() };
sensors.sar_meas_start1().read().meas1_data_sar().bits() as u16
unsafe { &*SENS::ptr() }
.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
unsafe { &*SENS::ptr() }
.sar_start_force()
.modify(|_, w| unsafe { w.sar2_bit_width().bits(resolution) });
}
fn set_sample_bit(resolution: u8) {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.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| {
unsafe { &*SENS::ptr() }.sar_atten2().modify(|r, w| {
let new_value = (r.bits() & !(0b11 << (channel * 2)))
| (((attenuation as u8 & 0b11) as u32) << (channel * 2));
@ -210,50 +193,43 @@ impl RegisterAccess for ADC2 {
}
fn clear_dig_force() {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.sar_read_ctrl2()
.modify(|_, w| w.sar2_dig_force().clear_bit());
}
fn set_start_force() {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.sar_meas_start2()
.modify(|_, w| w.meas2_start_force().set_bit());
}
fn set_en_pad_force() {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.sar_meas_start2()
.modify(|_, w| w.sar2_en_pad_force().set_bit());
}
fn set_en_pad(channel: u8) {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.sar_meas_start2()
.modify(|_, w| unsafe { w.sar2_en_pad().bits(1 << channel) });
}
fn clear_start_sar() {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.sar_meas_start2()
.modify(|_, w| w.meas2_start_sar().clear_bit());
}
fn set_start_sar() {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.sar_meas_start2()
.modify(|_, w| w.meas2_start_sar().set_bit());
}
fn read_done_sar() -> bool {
let sensors = unsafe { &*SENS::ptr() };
sensors
unsafe { &*SENS::ptr() }
.sar_meas_start2()
.read()
.meas2_done_sar()
@ -261,11 +237,15 @@ impl RegisterAccess for ADC2 {
}
fn read_data_sar() -> u16 {
let sensors = unsafe { &*SENS::ptr() };
sensors.sar_meas_start2().read().meas2_data_sar().bits() as u16
unsafe { &*SENS::ptr() }
.sar_meas_start2()
.read()
.meas2_data_sar()
.bits() as u16
}
}
/// Analog-to-Digital Converter peripheral driver.
pub struct ADC<'d, ADC> {
_adc: PeripheralRef<'d, ADC>,
attenuations: [Option<Attenuation>; 10],
@ -355,25 +335,29 @@ where
impl<'d, ADC1> ADC<'d, ADC1> {
pub fn enable_hall_sensor() {
// Connect hall sensor
let rtcio = unsafe { &*RTC_IO::ptr() };
rtcio.hall_sens().modify(|_, w| w.xpd_hall().set_bit());
unsafe { &*RTC_IO::ptr() }
.hall_sens()
.modify(|_, w| w.xpd_hall().set_bit());
}
pub fn disable_hall_sensor() {
// Disconnect hall sensor
let rtcio = unsafe { &*RTC_IO::ptr() };
rtcio.hall_sens().modify(|_, w| w.xpd_hall().clear_bit());
unsafe { &*RTC_IO::ptr() }
.hall_sens()
.modify(|_, w| w.xpd_hall().clear_bit());
}
}
impl<'d, ADCI, PIN> OneShot<ADCI, u16, AdcPin<PIN, ADCI>> for ADC<'d, ADCI>
impl<'d, ADCI, PIN> embedded_hal::adc::OneShot<ADCI, u16, AdcPin<PIN, ADCI>> for ADC<'d, ADCI>
where
PIN: Channel<ADCI, ID = u8>,
PIN: embedded_hal::adc::Channel<ADCI, ID = u8>,
ADCI: RegisterAccess,
{
type Error = ();
fn read(&mut self, _pin: &mut AdcPin<PIN, ADCI>) -> nb::Result<u16, Self::Error> {
use embedded_hal::adc::Channel;
if self.attenuations[AdcPin::<PIN, ADCI>::channel() as usize] == None {
panic!(
"Channel {} is not configured reading!",
@ -418,8 +402,11 @@ macro_rules! impl_adc_interface {
($adc:ident [
$( ($pin:ident, $channel:expr) ,)+
]) => {
$(
impl $crate::analog::adc::AdcChannel for crate::gpio::$pin<crate::gpio::Analog> {
const CHANNEL: u8 = $channel;
}
impl embedded_hal::adc::Channel<$adc> for crate::gpio::$pin<crate::gpio::Analog> {
type ID = u8;
@ -430,54 +417,7 @@ macro_rules! impl_adc_interface {
}
mod implementation {
//! # Analog to digital (ADC) conversion support.
//!
//! ## Overview
//! The `ADC` module in the `analog` driver enables users to perform
//! analog-to-digital conversions, allowing them to measure real-world
//! analog signals with high accuracy.
//!
//! This module provides functions for reading analog values from the
//! analog to digital converter 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 |
//!
//! ## Example
//! #### ADC on Xtensa architecture
//! ```no_run
//! // Create ADC instances
//! let analog = peripherals.SENS.split();
//!
//! let mut adc1_config = AdcConfig::new();
//!
//! let mut pin3 =
//! adc1_config.enable_pin(io.pins.gpio3.into_analog(), Attenuation::Attenuation11dB);
//!
//! let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
//!
//! let mut delay = Delay::new(&clocks);
//!
//! loop {
//! let pin3_value: u16 = nb::block!(adc1.read(&mut pin3)).unwrap();
//! println!("PIN3 ADC reading = {}", pin3_value);
//! delay.delay_ms(1500u32);
//! }
//! ```
use crate::analog::{ADC1, ADC2};
use crate::peripherals::{ADC1, ADC2};
impl_adc_interface! {
ADC1 [
@ -494,9 +434,9 @@ mod implementation {
impl_adc_interface! {
ADC2 [
(Gpio4, 0),
(Gpio0, 1),
(Gpio2, 2),
(Gpio4, 0),
(Gpio0, 1),
(Gpio2, 2),
(Gpio15, 3), // Alt. name: MTDO
(Gpio13, 4), // Alt. name: MTCK
(Gpio12, 5), // Alt. name: MTDI

View File

@ -0,0 +1,108 @@
//! # Analog to Digital Converter (ADC)
//!
//! The Analog to Digital Converter (ADC) is integrated on the chip, and is
//! capable of measuring analog signals from specific analog I/O pins. One or
//! more ADC units are available, depending on the device being used.
//!
//! ## Example
//!
//! ```no_run
//! let mut adc1_config = AdcConfig::new();
//! let mut adc1 = ADC::<ADC1>::adc(peripherals.ADC1, adc1_config).unwrap();
//! let mut pin = adc1_config.enable_pin(io.pins.gpio2.into_analog(), Attenuation::Attenuation11dB);
//!
//! let mut delay = Delay::new(&clocks);
//!
//! loop {
//! let pin_value: u16 = nb::block!(adc1.read(&mut pin)).unwrap();
//! println!("PIN2 ADC reading = {}", pin_value);
//!
//! delay.delay_ms(1500u32);
//! }
//! ```
pub use self::implementation::*;
#[cfg_attr(esp32, path = "esp32.rs")]
#[cfg_attr(riscv, path = "riscv.rs")]
#[cfg_attr(any(esp32s2, esp32s3), path = "xtensa.rs")]
mod implementation;
mod private {
pub trait Sealed {}
}
/// The attenuation of the ADC pin.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Attenuation {
/// 0dB attenuation, measurement range: 0-800mV
Attenuation0dB = 0b00,
/// 2.5dB attenuation, measurement range: 0-1100mV
#[cfg(not(esp32c2))]
Attenuation2p5dB = 0b01,
/// 6dB attenuation, measurement range: 0-1350mV
#[cfg(not(esp32c2))]
Attenuation6dB = 0b10,
/// 11dB attenuation, measurement range: 0-2600mV
Attenuation11dB = 0b11,
}
/// Calibration source of the ADC.
#[cfg(not(esp32))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AdcCalSource {
Gnd,
Ref,
}
/// A helper trait to get the ADC channel of a compatible GPIO pin.
pub trait AdcChannel {
const CHANNEL: u8;
}
/// A trait abstracting over calibration methods.
///
/// The methods in this trait are mostly for internal use. To get
/// calibrated ADC reads, all you need to do is call `enable_pin_with_cal`
/// and specify some implementor of this trait.
pub trait AdcCalScheme<ADCI>: Sized + private::Sealed {
/// Create a new calibration scheme for the given attenuation.
fn new_cal(atten: Attenuation) -> Self;
/// Return the basic ADC bias value. See [`AdcCalBasic`] for
/// details.
fn adc_cal(&self) -> u16 {
0
}
/// Convert ADC value
fn adc_val(&self, val: u16) -> u16 {
val
}
}
impl private::Sealed for () {}
impl<ADCI> AdcCalScheme<ADCI> for () {
fn new_cal(_atten: Attenuation) -> Self {
()
}
}
/// A helper trait to get access to ADC calibration efuses.
trait AdcCalEfuse {
/// Get ADC calibration init code
///
/// Returns digital value for zero voltage for a given attenuation
fn get_init_code(atten: Attenuation) -> Option<u16>;
/// Get ADC calibration reference point voltage
///
/// Returns reference voltage (millivolts) for a given attenuation
fn get_cal_mv(atten: Attenuation) -> u16;
/// Get ADC calibration reference point digital value
///
/// Returns digital value for reference voltage for a given attenuation
fn get_cal_code(atten: Attenuation) -> Option<u16>;
}

View File

@ -1,10 +1,7 @@
use core::marker::PhantomData;
use embedded_hal::adc::{Channel, OneShot};
pub use crate::analog::ADC1;
#[cfg(esp32c3)]
pub use crate::analog::ADC2;
pub use self::calibration::*;
use super::{AdcCalEfuse, AdcCalScheme, AdcCalSource, AdcChannel, Attenuation};
#[cfg(any(esp32c6, esp32h2))]
use crate::clock::clocks_ll::regi2c_write_mask;
#[cfg(any(esp32c2, esp32c3, esp32c6))]
@ -15,21 +12,7 @@ use crate::{
system::{Peripheral, PeripheralClockControl},
};
#[cfg(any(esp32c2, esp32c3, esp32c6))]
mod cal_basic;
#[cfg(any(esp32c3, esp32c6))]
mod cal_curve;
#[cfg(any(esp32c2, esp32c3, esp32c6))]
mod cal_line;
#[cfg(any(esp32c2, esp32c3, esp32c6))]
pub use cal_basic::AdcCalBasic;
#[cfg(any(esp32c3, esp32c6))]
pub use cal_curve::{AdcCalCurve, AdcHasCurveCal};
#[cfg(any(esp32c2, esp32c3, esp32c6))]
pub use cal_line::{AdcCalLine, AdcHasLineCal};
pub use crate::analog::{AdcCalEfuse, AdcCalScheme};
mod calibration;
// polyfill for c2 and c3
#[cfg(any(esp32c2, esp32c3))]
@ -118,48 +101,22 @@ cfg_if::cfg_if! {
}
}
/// The sampling/readout resolution of the ADC
/// The sampling/readout resolution of the ADC.
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum Resolution {
Resolution12Bit,
}
/// The attenuation of the ADC pin
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum Attenuation {
/// 0 dB attenuation, measurement range: 0 - 800 mV
Attenuation0dB = 0b00,
/// 2.5 dB attenuation, measurement range: 0 - 1100 mV
#[cfg(not(esp32c2))]
Attenuation2p5dB = 0b01,
/// 6 dB attenuation, measurement range: 0 - 1350 mV
#[cfg(not(esp32c2))]
Attenuation6dB = 0b10,
/// 11 dB attenuation, measurement range: 0 - 2600 mV
Attenuation11dB = 0b11,
}
impl Attenuation {
/// List of all supported attenuations
pub const ALL: &'static [Attenuation] = &[
Attenuation::Attenuation0dB,
#[cfg(not(esp32c2))]
Attenuation::Attenuation2p5dB,
#[cfg(not(esp32c2))]
Attenuation::Attenuation6dB,
Attenuation::Attenuation11dB,
];
}
/// An I/O pin which can be read using the ADC.
pub struct AdcPin<PIN, ADCI, CS = ()> {
pub pin: PIN,
pub cal_scheme: CS,
_phantom: PhantomData<ADCI>,
}
impl<PIN, ADCI, CS> Channel<ADCI> for AdcPin<PIN, ADCI, CS>
impl<PIN, ADCI, CS> embedded_hal::adc::Channel<ADCI> for AdcPin<PIN, ADCI, CS>
where
PIN: Channel<ADCI, ID = u8>,
PIN: embedded_hal::adc::Channel<ADCI, ID = u8>,
{
type ID = u8;
@ -168,6 +125,7 @@ where
}
}
/// Configuration for the ADC.
pub struct AdcConfig<ADCI> {
pub resolution: Resolution,
pub attenuations: [Option<Attenuation>; NUM_ATTENS],
@ -184,9 +142,9 @@ where
pub fn enable_pin<PIN>(&mut self, pin: PIN, attenuation: Attenuation) -> AdcPin<PIN, ADCI>
where
PIN: Channel<ADCI, ID = u8>,
PIN: AdcChannel,
{
self.attenuations[PIN::channel() as usize] = Some(attenuation);
self.attenuations[PIN::CHANNEL as usize] = Some(attenuation);
AdcPin {
pin,
@ -202,10 +160,10 @@ where
) -> AdcPin<PIN, ADCI, CS>
where
ADCI: CalibrationAccess,
PIN: Channel<ADCI, ID = u8>,
PIN: AdcChannel,
CS: AdcCalScheme<ADCI>,
{
self.attenuations[PIN::channel() as usize] = Some(attenuation);
self.attenuations[PIN::CHANNEL as usize] = Some(attenuation);
AdcPin {
pin,
@ -268,12 +226,6 @@ impl<ADCI> Default for AdcConfig<ADCI> {
}
}
#[derive(Clone, Copy)]
pub enum AdcCalSource {
Gnd,
Ref,
}
#[doc(hidden)]
pub trait RegisterAccess {
/// Configure onetime sampling parameters
@ -295,6 +247,7 @@ pub trait RegisterAccess {
fn set_init_code(data: u16);
}
#[doc(hidden)]
pub trait CalibrationAccess: RegisterAccess {
const ADC_CAL_CNT_MAX: u16;
const ADC_CAL_CHANNEL: u16;
@ -306,7 +259,7 @@ pub trait CalibrationAccess: RegisterAccess {
fn connect_cal(source: AdcCalSource, enable: bool);
}
impl RegisterAccess for ADC1 {
impl RegisterAccess for crate::peripherals::ADC1 {
fn config_onetime_sample(channel: u8, attenuation: u8) {
let sar_adc = unsafe { &*APB_SARADC::PTR };
@ -376,7 +329,7 @@ impl RegisterAccess for ADC1 {
}
}
impl CalibrationAccess for ADC1 {
impl CalibrationAccess for crate::peripherals::ADC1 {
const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
@ -417,7 +370,7 @@ impl CalibrationAccess for ADC1 {
}
#[cfg(esp32c3)]
impl RegisterAccess for ADC2 {
impl RegisterAccess for crate::peripherals::ADC2 {
fn config_onetime_sample(channel: u8, attenuation: u8) {
let sar_adc = unsafe { &*APB_SARADC::PTR };
@ -486,7 +439,7 @@ impl RegisterAccess for ADC2 {
}
#[cfg(esp32c3)]
impl CalibrationAccess for ADC2 {
impl CalibrationAccess for crate::peripherals::ADC2 {
const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
@ -526,6 +479,7 @@ impl CalibrationAccess for ADC2 {
}
}
/// Analog-to-Digital Converter peripheral driver.
pub struct ADC<'d, ADCI> {
_adc: PeripheralRef<'d, ADCI>,
attenuations: [Option<Attenuation>; NUM_ATTENS],
@ -564,7 +518,7 @@ where
}
#[cfg(any(esp32c2, esp32c3, esp32c6))]
impl AdcCalEfuse for ADC1 {
impl AdcCalEfuse for crate::peripherals::ADC1 {
fn get_init_code(atten: Attenuation) -> Option<u16> {
Efuse::get_rtc_calib_init_code(1, atten)
}
@ -579,7 +533,7 @@ impl AdcCalEfuse for ADC1 {
}
#[cfg(esp32c3)]
impl AdcCalEfuse for ADC2 {
impl AdcCalEfuse for crate::peripherals::ADC2 {
fn get_init_code(atten: Attenuation) -> Option<u16> {
Efuse::get_rtc_calib_init_code(2, atten)
}
@ -593,15 +547,18 @@ impl AdcCalEfuse for ADC2 {
}
}
impl<'d, ADCI, PIN, CS> OneShot<ADCI, u16, AdcPin<PIN, ADCI, CS>> for ADC<'d, ADCI>
impl<'d, ADCI, PIN, CS> embedded_hal::adc::OneShot<ADCI, u16, AdcPin<PIN, ADCI, CS>>
for ADC<'d, ADCI>
where
PIN: Channel<ADCI, ID = u8>,
PIN: embedded_hal::adc::Channel<ADCI, ID = u8>,
ADCI: RegisterAccess,
CS: AdcCalScheme<ADCI>,
{
type Error = ();
fn read(&mut self, pin: &mut AdcPin<PIN, ADCI, CS>) -> nb::Result<u16, Self::Error> {
use embedded_hal::adc::Channel;
if self.attenuations[AdcPin::<PIN, ADCI>::channel() as usize] == None {
panic!(
"Channel {} is not configured reading!",
@ -676,8 +633,11 @@ macro_rules! impl_adc_interface {
($adc:ident [
$( ($pin:ident, $channel:expr) ,)+
]) => {
$(
impl $crate::analog::adc::AdcChannel for crate::gpio::$pin<crate::gpio::Analog> {
const CHANNEL: u8 = $channel;
}
impl embedded_hal::adc::Channel<$adc> for crate::gpio::$pin<crate::gpio::Analog> {
type ID = u8;
@ -689,38 +649,7 @@ macro_rules! impl_adc_interface {
#[cfg(esp32c2)]
mod implementation {
//! # Analog to digital (ADC) conversion support.
//!
//! ## Overview
//! The `ADC` module in the `analog` driver enables users to perform
//! analog-to-digital conversions, allowing them to measure real-world
//! analog signals with high accuracy.
//!
//! This module provides functions for reading analog values from the
//! analog to digital converter available on the ESP32-C2: `ADC1`.
//!
//! ## Example
//! #### ADC on Risc-V architecture
//! ```no_run
//! // Create ADC instances
//! let analog = peripherals.APB_SARADC.split();
//!
//! let mut adc1_config = AdcConfig::new();
//!
//! let mut pin = adc1_config.enable_pin(io.pins.gpio2.into_analog(), Attenuation::Attenuation11dB);
//!
//! let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
//!
//! let mut delay = Delay::new(&clocks);
//!
//! loop {
//! let pin_value: u16 = nb::block!(adc1.read(&mut pin)).unwrap();
//! println!("PIN2 ADC reading = {}", pin_value);
//! delay.delay_ms(1500u32);
//! }
//! ```
use crate::analog::ADC1;
use crate::peripherals::ADC1;
impl_adc_interface! {
ADC1 [
@ -735,39 +664,7 @@ mod implementation {
#[cfg(esp32c3)]
mod implementation {
//! # Analog to digital (ADC) conversion support.
//!
//! ## Overview
//! The `ADC` module in the `analog` driver enables users to perform
//! analog-to-digital conversions, allowing them to measure real-world
//! analog signals with high accuracy.
//!
//! This module provides functions for reading analog values from the
//! analog to digital converter available on the ESP32-C3: `ADC1` and
//! `ADC2`.
//!
//! ## Example
//! #### ADC on Risc-V architecture
//! ```no_run
//! // Create ADC instances
//! let analog = peripherals.APB_SARADC.split();
//!
//! let mut adc1_config = AdcConfig::new();
//!
//! let mut pin = adc1_config.enable_pin(io.pins.gpio2.into_analog(), Attenuation::Attenuation11dB);
//!
//! let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
//!
//! let mut delay = Delay::new(&clocks);
//!
//! loop {
//! let pin_value: u16 = nb::block!(adc1.read(&mut pin)).unwrap();
//! println!("PIN2 ADC reading = {}", pin_value);
//! delay.delay_ms(1500u32);
//! }
//! ```
use crate::analog::{ADC1, ADC2};
use crate::peripherals::{ADC1, ADC2};
impl_adc_interface! {
ADC1 [
@ -788,38 +685,7 @@ mod implementation {
#[cfg(esp32c6)]
mod implementation {
//! # Analog to digital (ADC) conversion support.
//!
//! ## Overview
//! The `ADC` module in the `analog` driver enables users to perform
//! analog-to-digital conversions, allowing them to measure real-world
//! analog signals with high accuracy.
//!
//! This module provides functions for reading analog values from the
//! analog to digital converter available on the ESP32-C6: `ADC1`.
//!
//! ## Example
//! #### ADC on Risc-V architecture
//! ```no_run
//! // Create ADC instances
//! let analog = peripherals.APB_SARADC.split();
//!
//! let mut adc1_config = AdcConfig::new();
//!
//! let mut pin = adc1_config.enable_pin(io.pins.gpio2.into_analog(), Attenuation::Attenuation11dB);
//!
//! let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
//!
//! let mut delay = Delay::new(&clocks);
//!
//! loop {
//! let pin_value: u16 = nb::block!(adc1.read(&mut pin)).unwrap();
//! println!("PIN2 ADC reading = {}", pin_value);
//! delay.delay_ms(1500u32);
//! }
//! ```
use crate::analog::ADC1;
use crate::peripherals::ADC1;
impl_adc_interface! {
ADC1 [
@ -836,38 +702,7 @@ mod implementation {
#[cfg(esp32h2)]
mod implementation {
//! # Analog to digital (ADC) conversion support.
//!
//! ## Overview
//! The `ADC` module in the `analog` driver enables users to perform
//! analog-to-digital conversions, allowing them to measure real-world
//! analog signals with high accuracy.
//!
//! This module provides functions for reading analog values from the
//! analog to digital converter available on the ESP32-H2: `ADC1`.
//!
//! ## Example
//! #### ADC on Risc-V architecture
//! ```no_run
//! // Create ADC instances
//! let analog = peripherals.APB_SARADC.split();
//!
//! let mut adc1_config = AdcConfig::new();
//!
//! let mut pin = adc1_config.enable_pin(io.pins.gpio2.into_analog(), Attenuation::Attenuation11dB);
//!
//! let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
//!
//! let mut delay = Delay::new(&clocks);
//!
//! loop {
//! let pin_value: u16 = nb::block!(adc1.read(&mut pin)).unwrap();
//! println!("PIN2 ADC reading = {}", pin_value);
//! delay.delay_ms(1500u32);
//! }
//! ```
use crate::analog::ADC1;
use crate::peripherals::ADC1;
impl_adc_interface! {
ADC1 [

View File

@ -1,8 +1,9 @@
use core::marker::PhantomData;
use embedded_hal::adc::{Channel, OneShot};
pub use crate::analog::{ADC1, ADC2};
pub use self::calibration::*;
#[cfg(esp32s3)]
use super::AdcCalEfuse;
use super::{AdcCalScheme, AdcCalSource, AdcChannel, Attenuation};
#[cfg(esp32s3)]
use crate::efuse::Efuse;
use crate::{
@ -10,21 +11,7 @@ use crate::{
peripherals::{APB_SARADC, SENS},
};
#[cfg(esp32s3)]
mod cal_basic;
#[cfg(esp32s3)]
mod cal_curve;
#[cfg(esp32s3)]
mod cal_line;
#[cfg(esp32s3)]
pub use cal_basic::AdcCalBasic;
#[cfg(esp32s3)]
pub use cal_curve::{AdcCalCurve, AdcHasCurveCal};
#[cfg(esp32s3)]
pub use cal_line::{AdcCalLine, AdcHasLineCal};
pub use crate::analog::{AdcCalEfuse, AdcCalScheme};
mod calibration;
// Constants taken from:
// https://github.com/espressif/esp-idf/blob/903af13e8/components/soc/esp32s2/include/soc/regi2c_saradc.h
@ -85,44 +72,22 @@ cfg_if::cfg_if! {
}
}
/// The sampling/readout resolution of the ADC
/// 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 {
/// 0 dB attenuation, measurement range: 0 - 800 mV
Attenuation0dB = 0b00,
/// 2.5 dB attenuation, measurement range: 0 - 1100 mV
Attenuation2p5dB = 0b01,
/// 6 dB attenuation, measurement range: 0 - 1350 mV
Attenuation6dB = 0b10,
/// 11 dB attenuation, measurement range: 0 - 2600 mV
Attenuation11dB = 0b11,
}
impl Attenuation {
/// List of all supported attenuations
pub const ALL: &'static [Attenuation] = &[
Attenuation::Attenuation0dB,
Attenuation::Attenuation2p5dB,
Attenuation::Attenuation6dB,
Attenuation::Attenuation11dB,
];
}
/// An I/O pin which can be read using the ADC.
pub struct AdcPin<PIN, ADCI, CS = ()> {
pub pin: PIN,
pub cal_scheme: CS,
_phantom: PhantomData<ADCI>,
}
impl<PIN, ADCI, CS> Channel<ADCI> for AdcPin<PIN, ADCI, CS>
impl<PIN, ADCI, CS> embedded_hal::adc::Channel<ADCI> for AdcPin<PIN, ADCI, CS>
where
PIN: Channel<ADCI, ID = u8>,
PIN: embedded_hal::adc::Channel<ADCI, ID = u8>,
{
type ID = u8;
@ -131,6 +96,7 @@ where
}
}
/// Configuration for the ADC.
pub struct AdcConfig<ADCI> {
pub resolution: Resolution,
pub attenuations: [Option<Attenuation>; 10],
@ -147,9 +113,9 @@ where
pub fn enable_pin<PIN>(&mut self, pin: PIN, attenuation: Attenuation) -> AdcPin<PIN, ADCI>
where
PIN: Channel<ADCI, ID = u8>,
PIN: AdcChannel,
{
self.attenuations[PIN::channel() as usize] = Some(attenuation);
self.attenuations[PIN::CHANNEL as usize] = Some(attenuation);
AdcPin {
pin,
@ -165,10 +131,10 @@ where
) -> AdcPin<PIN, ADCI, CS>
where
ADCI: CalibrationAccess,
PIN: Channel<ADCI, ID = u8>,
PIN: AdcChannel,
CS: AdcCalScheme<ADCI>,
{
self.attenuations[PIN::channel() as usize] = Some(attenuation);
self.attenuations[PIN::CHANNEL as usize] = Some(attenuation);
AdcPin {
pin,
@ -233,12 +199,6 @@ impl<ADCI> Default for AdcConfig<ADCI> {
}
}
#[derive(Clone, Copy)]
pub enum AdcCalSource {
Gnd,
Ref,
}
#[doc(hidden)]
pub trait RegisterAccess {
fn adc_samplecfg(channel: u16);
@ -270,6 +230,7 @@ pub trait RegisterAccess {
fn reset();
}
#[doc(hidden)]
pub trait CalibrationAccess: RegisterAccess {
const ADC_CAL_CNT_MAX: u16;
const ADC_CAL_CHANNEL: u16;
@ -281,7 +242,7 @@ pub trait CalibrationAccess: RegisterAccess {
fn connect_cal(source: AdcCalSource, enable: bool);
}
impl RegisterAccess for ADC1 {
impl RegisterAccess for crate::peripherals::ADC1 {
fn adc_samplecfg(channel: u16) {
let sensors = unsafe { &*SENS::ptr() };
@ -395,7 +356,7 @@ impl RegisterAccess for ADC1 {
}
#[cfg(esp32s3)]
impl CalibrationAccess for ADC1 {
impl CalibrationAccess for crate::peripherals::ADC1 {
const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
@ -416,7 +377,7 @@ impl CalibrationAccess for ADC1 {
}
}
impl RegisterAccess for ADC2 {
impl RegisterAccess for crate::peripherals::ADC2 {
fn adc_samplecfg(channel: u16) {
let sensors = unsafe { &*SENS::ptr() };
@ -531,7 +492,7 @@ impl RegisterAccess for ADC2 {
}
#[cfg(esp32s3)]
impl CalibrationAccess for ADC2 {
impl CalibrationAccess for crate::peripherals::ADC2 {
const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
@ -552,6 +513,7 @@ impl CalibrationAccess for ADC2 {
}
}
/// Analog-to-Digital Converter peripheral driver.
pub struct ADC<'d, ADC> {
_adc: PeripheralRef<'d, ADC>,
attenuations: [Option<Attenuation>; 10],
@ -641,7 +603,7 @@ where
}
#[cfg(esp32s3)]
impl AdcCalEfuse for ADC1 {
impl AdcCalEfuse for crate::peripherals::ADC1 {
fn get_init_code(atten: Attenuation) -> Option<u16> {
Efuse::get_rtc_calib_init_code(1, atten)
}
@ -656,7 +618,7 @@ impl AdcCalEfuse for ADC1 {
}
#[cfg(esp32s3)]
impl AdcCalEfuse for ADC2 {
impl AdcCalEfuse for crate::peripherals::ADC2 {
fn get_init_code(atten: Attenuation) -> Option<u16> {
Efuse::get_rtc_calib_init_code(2, atten)
}
@ -670,15 +632,18 @@ impl AdcCalEfuse for ADC2 {
}
}
impl<'d, ADCI, PIN, CS> OneShot<ADCI, u16, AdcPin<PIN, ADCI, CS>> for ADC<'d, ADCI>
impl<'d, ADCI, PIN, CS> embedded_hal::adc::OneShot<ADCI, u16, AdcPin<PIN, ADCI, CS>>
for ADC<'d, ADCI>
where
PIN: Channel<ADCI, ID = u8>,
PIN: embedded_hal::adc::Channel<ADCI, ID = u8>,
ADCI: RegisterAccess,
CS: AdcCalScheme<ADCI>,
{
type Error = ();
fn read(&mut self, pin: &mut AdcPin<PIN, ADCI, CS>) -> nb::Result<u16, Self::Error> {
use embedded_hal::adc::Channel;
if self.attenuations[AdcPin::<PIN, ADCI>::channel() as usize] == None {
panic!(
"Channel {} is not configured reading!",
@ -732,6 +697,10 @@ macro_rules! impl_adc_interface {
]) => {
$(
impl $crate::analog::adc::AdcChannel for crate::gpio::$pin<crate::gpio::Analog> {
const CHANNEL: u8 = $channel;
}
impl embedded_hal::adc::Channel<$adc> for crate::gpio::$pin<crate::gpio::Analog> {
type ID = u8;
@ -741,125 +710,21 @@ macro_rules! impl_adc_interface {
}
}
pub use implementation::*;
#[cfg(esp32s3)]
mod implementation {
//! # Analog to digital (ADC) conversion support.
//!
//! ## Overview
//! The `ADC` module in the `analog` driver enables users to perform
//! analog-to-digital conversions, allowing them to measure real-world
//! analog signals with high accuracy.
//!
//! This module provides functions for reading analog values from the
//! analog to digital converter available on the ESP32-S3: `ADC1` and
//! `ADC2`.
//!
//! ## Example
//! #### ADC on Xtensa architecture
//! ```no_run
//! // Create ADC instances
//! let analog = peripherals.SENS.split();
//!
//! let mut adc1_config = AdcConfig::new();
//!
//! let mut pin3 =
//! adc1_config.enable_pin(io.pins.gpio3.into_analog(), Attenuation::Attenuation11dB);
//!
//! let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
//!
//! let mut delay = Delay::new(&clocks);
//!
//! loop {
//! let pin3_value: u16 = nb::block!(adc1.read(&mut pin3)).unwrap();
//! println!("PIN3 ADC reading = {}", pin3_value);
//! delay.delay_ms(1500u32);
//! }
//! ```
use crate::analog::{ADC1, ADC2};
use crate::peripherals::{ADC1, ADC2};
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),
]
}
}
#[cfg(esp32s2)]
mod implementation {
//! # Analog to digital (ADC) conversion support.
//!
//! ## Overview
//! The `ADC` module in the `analog` driver enables users to perform
//! analog-to-digital conversions, allowing them to measure real-world
//! analog signals with high accuracy.
//!
//! This module provides functions for reading analog values from the
//! analog to digital converter available on the ESP32-S2: `ADC1` and
//! `ADC2`.
//!
//! ## Example
//! #### ADC on Xtensa architecture
//! ```no_run
//! // Create ADC instances
//! let analog = peripherals.SENS.split();
//!
//! let mut adc1_config = AdcConfig::new();
//!
//! let mut pin3 =
//! adc1_config.enable_pin(io.pins.gpio3.into_analog(), Attenuation::Attenuation11dB);
//!
//! let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
//!
//! let mut delay = Delay::new(&clocks);
//!
//! loop {
//! let pin3_value: u16 = nb::block!(adc1.read(&mut pin3)).unwrap();
//! println!("PIN3 ADC reading = {}", pin3_value);
//! delay.delay_ms(1500u32);
//! }
//! ```
use crate::analog::{ADC1, ADC2};
impl_adc_interface! {
ADC1 [
(Gpio1, 0),
(Gpio2, 1),
(Gpio3, 2),
(Gpio4, 3),
(Gpio5, 4),
(Gpio6, 5),
(Gpio7, 6),
(Gpio8, 7),
(Gpio9, 8),
(Gpio10,9),
(Gpio1, 0),
(Gpio2, 1),
(Gpio3, 2),
(Gpio4, 3),
(Gpio5, 4),
(Gpio6, 5),
(Gpio7, 6),
(Gpio8, 7),
(Gpio9, 8),
(Gpio10, 9),
]
}

View File

@ -1,159 +1,127 @@
//! # Analog peripherals - Digital to Analog Converter
//! # Digital to Analog Converter (DAC)
//!
//! ## Overview
//! The `DAC` module is part of the `Analog` driver designed for ESP
//! microcontrollers, providing functionalities for `digital-to-analog`
//! conversion.
//! The `dac` module enables users to generate analog output signals with
//! precise control over voltage levels using one of the onboard
//! digital-to-analog converters (DAC).
//!
//! This module simplifies digital-to-analog conversion on ESP microcontrollers,
//! enabling precise control over analog output signals. Developers can choose
//! the `DAC` channel they want to use based on the GPIO pin assignments for
//! each channel. By providing a unified interface for DAC control, the module
//! makes it easier for users to generate accurate analog voltages in their
//! applications, such as audio generation, sensor calibration, and analog
//! signal synthesis.
use crate::peripherals::{RTC_IO, SENS};
pub trait DAC {
fn write(&mut self, value: u8);
//! Two 8-bit DAC channels are available. Each DAC channel can convert the
//! digital value 0-255 to the analog voltage 0-3.3v. Developers can choose the
//! DAC channel they want to use based on the GPIO pin assignments for each
//! channel.
//!
//! ## Example
//!
//! ```no_run
//! let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
//! let gpio25 = io.pins.gpio25.into_analog();
//! let gpio26 = io.pins.gpio26.into_analog();
//!
//! let mut dac1 = DAC1::new(peripherals.DAC1, gpio25);
//! let mut dac2 = DAC2::new(peripherals.DAC2, gpio26);
//!
//! let mut delay = Delay::new(&clocks);
//!
//! let mut voltage_dac1 = 200u8;
//! let mut voltage_dac2 = 255u8;
//!
//! // Change voltage on the pins using write function:
//! loop {
//! voltage_dac1 = voltage_dac1.wrapping_add(1);
//! dac1.write(voltage_dac1);
//!
//! voltage_dac2 = voltage_dac2.wrapping_sub(1);
//! dac2.write(voltage_dac2);
//!
//! delay.delay_ms(50u32);
//! }
//! ```
use crate::{
gpio,
peripheral::{Peripheral, PeripheralRef},
peripherals,
};
cfg_if::cfg_if! {
if #[cfg(esp32)] {
type Dac1Gpio = gpio::Gpio25<gpio::Analog>;
type Dac2Gpio = gpio::Gpio26<gpio::Analog>;
} else if #[cfg(esp32s2)] {
type Dac1Gpio = gpio::Gpio17<gpio::Analog>;
type Dac2Gpio = gpio::Gpio18<gpio::Analog>;
}
}
trait DAC1Impl {
fn set_power(self) -> Self
where
Self: Sized,
{
/// Digital-to-Analog Converter (DAC) Channel 1
pub struct DAC1<'d> {
_inner: PeripheralRef<'d, peripherals::DAC1>,
}
impl<'d> DAC1<'d> {
/// Constructs a new DAC instance.
pub fn new(dac: impl Peripheral<P = peripherals::DAC1> + 'd, _pin: Dac1Gpio) -> Self {
crate::into_ref!(dac);
#[cfg(esp32s2)]
{
let sensors = unsafe { &*SENS::ptr() };
sensors
.sar_dac_ctrl1()
.modify(|_, w| w.dac_clkgate_en().set_bit());
}
unsafe { &*peripherals::SENS::PTR }
.sar_dac_ctrl1()
.modify(|_, w| w.dac_clkgate_en().set_bit());
let rtcio = unsafe { &*RTC_IO::ptr() };
unsafe { &*peripherals::RTC_IO::PTR }
.pad_dac1()
.modify(|_, w| w.pdac1_dac_xpd_force().set_bit().pdac1_xpd_dac().set_bit());
rtcio.pad_dac1().modify(|_, w| {
w.pdac1_dac_xpd_force().set_bit();
w.pdac1_xpd_dac().set_bit()
});
self
Self { _inner: dac }
}
fn write(&mut self, value: u8) {
let rtcio = unsafe { &*RTC_IO::ptr() };
let sensors = unsafe { &*SENS::ptr() };
sensors
/// Writes the given value.
///
/// For each DAC channel, the output analog voltage can be calculated as
/// follows: DACn_OUT = VDD3P3_RTC * PDACn_DAC/256
pub fn write(&mut self, value: u8) {
unsafe { &*crate::peripherals::SENS::PTR }
.sar_dac_ctrl2()
.modify(|_, w| w.dac_cw_en1().clear_bit());
rtcio
unsafe { &*crate::peripherals::RTC_IO::PTR }
.pad_dac1()
.modify(|_, w| unsafe { w.pdac1_dac().bits(value) });
}
}
trait DAC2Impl {
fn set_power(self) -> Self
where
Self: Sized,
{
/// Digital-to-Analog Converter (DAC) Channel 2
pub struct DAC2<'d> {
_inner: PeripheralRef<'d, peripherals::DAC2>,
}
impl<'d> DAC2<'d> {
/// Constructs a new DAC instance.
pub fn new(dac: impl Peripheral<P = peripherals::DAC2> + 'd, _pin: Dac2Gpio) -> Self {
crate::into_ref!(dac);
#[cfg(esp32s2)]
{
let sensors = unsafe { &*SENS::ptr() };
sensors
.sar_dac_ctrl1()
.modify(|_, w| w.dac_clkgate_en().set_bit());
}
unsafe { &*peripherals::SENS::PTR }
.sar_dac_ctrl1()
.modify(|_, w| w.dac_clkgate_en().set_bit());
let rtcio = unsafe { &*RTC_IO::ptr() };
unsafe { &*peripherals::RTC_IO::PTR }
.pad_dac2()
.modify(|_, w| w.pdac2_dac_xpd_force().set_bit().pdac2_xpd_dac().set_bit());
rtcio.pad_dac2().modify(|_, w| {
w.pdac2_dac_xpd_force().set_bit();
w.pdac2_xpd_dac().set_bit()
});
self
Self { _inner: dac }
}
fn write(&mut self, value: u8) {
let rtcio = unsafe { &*RTC_IO::ptr() };
let sensors = unsafe { &*SENS::ptr() };
sensors
/// Writes the given value.
///
/// For each DAC channel, the output analog voltage can be calculated as
/// follows: DACn_OUT = VDD3P3_RTC * PDACn_DAC/256
pub fn write(&mut self, value: u8) {
unsafe { &*crate::peripherals::SENS::PTR }
.sar_dac_ctrl2()
.modify(|_, w| w.dac_cw_en2().clear_bit());
rtcio
unsafe { &*crate::peripherals::RTC_IO::PTR }
.pad_dac2()
.modify(|_, w| unsafe { w.pdac2_dac().bits(value) });
}
}
macro_rules! impl_dac {
($($number:literal => $gpio:ident),+) => {
$(
paste::paste! {
use $crate::analog::dac::[<DAC $number Impl>];
#[doc = "DAC channel " $number]
pub struct [<DAC $number>]<'d, DAC> {
_dac: $crate::peripheral::PeripheralRef<'d, DAC>,
_private: ::core::marker::PhantomData<()>,
}
impl<'d, DAC> [<DAC $number Impl>] for [<DAC $number>]<'d, DAC> {}
impl<'d, DAC> [<DAC $number>]<'d, DAC> {
/// Constructs a new DAC instance
pub fn dac(
dac: impl $crate::peripheral::Peripheral<P = DAC> +'d,
_pin: $crate::gpio::$gpio<$crate::gpio::Analog>,
) -> Result<Self, ()> {
let dac = Self {
_dac: dac.into_ref(),
_private: ::core::marker::PhantomData,
}
.set_power();
Ok(dac)
}
/// Writes the given value
///
/// For each DAC channel, the output analog voltage can be calculated as follows:
/// DACn_OUT = VDD3P3_RTC * PDACn_DAC/256
pub fn write(&mut self, value: u8) {
[<DAC $number Impl>]::write(self, value)
}
}
}
)+
};
}
pub use implementation::*;
#[cfg(esp32)]
mod implementation {
//! Digital to analog (DAC) conversion.
//!
//! This module provides functions for controlling two digital to
//! analog converters, available on ESP32: `DAC1` and `DAC2`.
//!
//! The DAC1 is available on the GPIO pin 25, and DAC2 on pin 26.
impl_dac!(1 => Gpio25, 2 => Gpio26);
}
#[cfg(esp32s2)]
mod implementation {
//! Digital to analog (DAC) conversion.
//!
//! This module provides functions for controlling two digital to
//! analog converters, available on ESP32-S2: `DAC1` and `DAC2`.
//!
//! The DAC1 is available on the GPIO pin 17, and DAC2 on pin 18.
impl_dac!(1 => Gpio17, 2 => Gpio18);
}

View File

@ -1,260 +1,10 @@
//! # Analog peripherals
//! # Analog Peripherals
//!
//! ## Overview
//! The `Analog` Driver is a module designed for ESP microcontrollers, that
//! provides an interface to interact with analog peripherals on the chip. The
//! module includes support for `Analog-to-Digital Converters (ADC)` and
//! `Digital-to-Analog Converters (DAC)`, offering functionality for precise
//! analog measurements and generating analog output signals.
//!
//! The `ADC` module in the `analog` driver enables users to perform
//! analog-to-digital conversions, allowing them to measure real-world analog
//! signals with high accuracy. The module provides access to multiple ADC
//! units, such as `ADC1` and `ADC2`, which may differ based on the specific ESP
//! microcontroller being used.
//!
//! The `DAC` module in the `analog` driver enables users to generate
//! analog output signals with precise control over voltage levels. The module
//! supports multiple DAC units, such as `DAC1` and `DAC2`, which may vary
//! depending on the specific ESP microcontroller.
//!
//! #### Xtensa architecture
//! For ESP microcontrollers using the `Xtensa` architecture, the driver
//! provides access to the `SENS` peripheral, allowing users to split it into
//! independent parts using the [`AnalogExt`] trait. This extension trait
//! provides access to the following analog peripherals:
//! * ADC1
//! * ADC2
//! * DAC1
//! * DAC2
//!
//! #### RISC-V architecture
//! For ESP microcontrollers using the `RISC-V` architecture, the driver
//! provides access to the `APB_SARADC` peripheral. The `AnalogExt` trait allows
//! users to split this peripheral into independent parts, providing access to
//! the following analog peripheral:
//! * ADC1
//! * ADC2
//!
//! ## Examples
//! #### ADC on Risc-V architecture
//! ```no_run
//! // Create ADC instances
//! let analog = peripherals.APB_SARADC.split();
//!
//! let mut adc1_config = AdcConfig::new();
//!
//! let mut pin = adc1_config.enable_pin(io.pins.gpio2.into_analog(), Attenuation::Attenuation11dB);
//!
//! let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
//!
//! let mut delay = Delay::new(&clocks);
//!
//! loop {
//! let pin_value: u16 = nb::block!(adc1.read(&mut pin)).unwrap();
//! println!("PIN2 ADC reading = {}", pin_value);
//! delay.delay_ms(1500u32);
//! }
//! ```
//! #### ADC on Xtensa architecture
//! ```no_run
//! // Create ADC instances
//! let analog = peripherals.SENS.split();
//!
//! let mut adc1_config = AdcConfig::new();
//!
//! let mut pin3 =
//! adc1_config.enable_pin(io.pins.gpio3.into_analog(), Attenuation::Attenuation11dB);
//!
//! let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
//!
//! let mut delay = Delay::new(&clocks);
//!
//! loop {
//! let pin3_value: u16 = nb::block!(adc1.read(&mut pin3)).unwrap();
//! println!("PIN3 ADC reading = {}", pin3_value);
//! delay.delay_ms(1500u32);
//! }
//! ```
//! The `analog` module provides drivers for the various analog peripherals
//! available on the device. For more information about a peripheral driver,
//! please refer to the relevant module documentation.
#[cfg_attr(esp32, path = "adc/esp32.rs")]
#[cfg_attr(riscv, path = "adc/riscv.rs")]
#[cfg_attr(any(esp32s2, esp32s3), path = "adc/xtensa.rs")]
#[cfg(adc)]
pub mod adc;
#[cfg(dac)]
pub mod dac;
/// A trait abstracting over calibration methods.
///
/// The methods in this trait are mostly for internal use. To get
/// calibrated ADC reads, all you need to do is call `enable_pin_with_cal`
/// and specify some implementor of this trait.
pub trait AdcCalScheme<ADCI>: Sized {
/// Create a new calibration scheme for the given attenuation.
fn new_cal(atten: adc::Attenuation) -> Self;
/// Return the basic ADC bias value. See [`adc::AdcCalBasic`] for
/// details.
fn adc_cal(&self) -> u16 {
0
}
/// Convert ADC value
fn adc_val(&self, val: u16) -> u16 {
val
}
}
impl<ADCI> AdcCalScheme<ADCI> for () {
fn new_cal(_atten: adc::Attenuation) -> Self {
()
}
}
/// A helper trait to get access to ADC calibration efuses
pub trait AdcCalEfuse {
/// Get ADC calibration init code
///
/// Returns digital value for zero voltage for a given attenuation
fn get_init_code(atten: adc::Attenuation) -> Option<u16>;
/// Get ADC calibration reference point voltage
///
/// Returns reference voltage (millivolts) for a given attenuation
fn get_cal_mv(atten: adc::Attenuation) -> u16;
/// Get ADC calibration reference point digital value
///
/// Returns digital value for reference voltage for a given attenuation
fn get_cal_code(atten: adc::Attenuation) -> Option<u16>;
}
pub struct ADC1 {
_private: (),
}
pub struct ADC2 {
_private: (),
}
pub struct DAC1 {
_private: (),
}
pub struct DAC2 {
_private: (),
}
impl core::ops::Deref for ADC1 {
type Target = ADC1;
fn deref(&self) -> &Self::Target {
self
}
}
impl core::ops::DerefMut for ADC1 {
fn deref_mut(&mut self) -> &mut Self::Target {
self
}
}
impl crate::peripheral::Peripheral for ADC1 {
type P = ADC1;
#[inline]
unsafe fn clone_unchecked(&mut self) -> Self::P {
ADC1 { _private: () }
}
}
impl crate::peripheral::sealed::Sealed for ADC1 {}
impl crate::peripheral::Peripheral for ADC2 {
type P = ADC2;
#[inline]
unsafe fn clone_unchecked(&mut self) -> Self::P {
ADC2 { _private: () }
}
}
impl crate::peripheral::sealed::Sealed for ADC2 {}
impl crate::peripheral::Peripheral for DAC1 {
type P = DAC1;
#[inline]
unsafe fn clone_unchecked(&mut self) -> Self::P {
DAC1 { _private: () }
}
}
impl crate::peripheral::sealed::Sealed for DAC1 {}
impl crate::peripheral::Peripheral for DAC2 {
type P = DAC2;
#[inline]
unsafe fn clone_unchecked(&mut self) -> Self::P {
DAC2 { _private: () }
}
}
impl crate::peripheral::sealed::Sealed for DAC2 {}
/// Extension trait to split a SENS peripheral in independent parts
pub trait AnalogExt {
fn split(self) -> AvailableAnalog;
}
cfg_if::cfg_if! {
if #[cfg(xtensa)] {
pub struct AvailableAnalog {
pub adc1: ADC1,
pub adc2: ADC2,
pub dac1: DAC1,
pub dac2: DAC2,
}
impl AnalogExt for crate::peripherals::SENS {
fn split(self) -> AvailableAnalog {
AvailableAnalog {
adc1: ADC1 {
_private: (),
},
adc2: ADC2 {
_private: (),
},
dac1: DAC1 {
_private: (),
},
dac2: DAC2 {
_private: (),
},
}
}
}
}
}
cfg_if::cfg_if! {
if #[cfg(riscv)] {
pub struct AvailableAnalog {
pub adc1: ADC1,
#[cfg(esp32c3)]
pub adc2: ADC2,
}
impl AnalogExt for crate::peripherals::APB_SARADC {
fn split(self) -> AvailableAnalog {
AvailableAnalog {
adc1: ADC1 {
_private: (),
},
#[cfg(esp32c3)]
adc2: ADC2 {
_private: (),
},
}
}
}
}
}

View File

@ -27,8 +27,6 @@ pub use fugit::{
};
pub use nb;
#[cfg(any(apb_saradc, sens))]
pub use crate::analog::AnalogExt as _esp_hal_analog_AnalogExt;
#[cfg(any(dport, pcr, system))]
pub use crate::clock::Clock as _esp_hal_clock_Clock;
#[cfg(any(gdma, pdma))]

View File

@ -20,9 +20,14 @@ pub(crate) use self::peripherals::*;
// peripheral (no `PSRAM`, `RADIO`, etc. peripheral in the PACs), so we're
// creating "virtual peripherals" for them.
crate::peripherals! {
ADC1 <= virtual,
ADC2 <= virtual,
AES <= AES,
APB_CTRL <= APB_CTRL,
BB <= BB,
BT <= virtual,
DAC1 <= virtual,
DAC2 <= virtual,
EFUSE <= EFUSE,
FLASH_ENCRYPTION <= FLASH_ENCRYPTION,
FRC_TIMER <= FRC_TIMER,
@ -39,6 +44,7 @@ crate::peripherals! {
MCPWM1 <= MCPWM1,
NRX <= NRX,
PCNT <= PCNT,
PSRAM <= virtual,
RMT <= RMT,
RNG <= RNG,
RSA <= RSA,
@ -46,7 +52,6 @@ crate::peripherals! {
RTC_IO <= RTC_IO,
RTC_I2C <= RTC_I2C,
SDHOST <= SDHOST,
SENS <= SENS,
SHA <= SHA,
SLC <= SLC,
SLCHOST <= SLCHOST,
@ -54,7 +59,6 @@ crate::peripherals! {
SPI1 <= SPI1,
SPI2 <= SPI2,
SPI3 <= SPI3,
// SYSTEM is derived from DPORT:
SYSTEM <= DPORT,
TIMG0 <= TIMG0,
TIMG1 <= TIMG1,
@ -64,9 +68,5 @@ crate::peripherals! {
UART2 <= UART2,
UHCI0 <= UHCI0,
UHCI1 <= UHCI1,
// Virtual peripherals:
BT <= virtual,
PSRAM <= virtual,
WIFI <= virtual,
}

View File

@ -20,9 +20,10 @@ pub(crate) use self::peripherals::*;
// peripheral (no `PSRAM`, `RADIO`, etc. peripheral in the PACs), so we're
// creating "virtual peripherals" for them.
crate::peripherals! {
ADC1 <= virtual,
APB_CTRL <= APB_CTRL,
APB_SARADC <= APB_SARADC,
ASSIST_DEBUG <= ASSIST_DEBUG,
BT <= virtual,
DMA <= DMA,
ECC <= ECC,
EFUSE <= EFUSE,
@ -44,9 +45,6 @@ crate::peripherals! {
TIMG0 <= TIMG0,
UART0 <= UART0,
UART1 <= UART1,
XTS_AES <= XTS_AES,
// Virtual peripherals:
BT <= virtual,
WIFI <= virtual,
XTS_AES <= XTS_AES,
}

View File

@ -20,10 +20,12 @@ pub(crate) use self::peripherals::*;
// peripheral (no `PSRAM`, `RADIO`, etc. peripheral in the PACs), so we're
// creating "virtual peripherals" for them.
crate::peripherals! {
ADC1 <= virtual,
ADC2 <= virtual,
AES <= AES,
APB_CTRL <= APB_CTRL,
APB_SARADC <= APB_SARADC,
ASSIST_DEBUG <= ASSIST_DEBUG,
BT <= virtual,
DMA <= DMA,
DS <= DS,
EFUSE <= EFUSE,
@ -55,9 +57,6 @@ crate::peripherals! {
UHCI0 <= UHCI0,
UHCI1 <= UHCI1,
USB_DEVICE <= USB_DEVICE,
XTS_AES <= XTS_AES,
// Virtual peripherals:
BT <= virtual,
WIFI <= virtual,
XTS_AES <= XTS_AES,
}

View File

@ -20,10 +20,11 @@ pub(crate) use self::peripherals::*;
// peripheral (no `PSRAM`, `RADIO`, etc. peripheral in the PACs), so we're
// creating "virtual peripherals" for them.
crate::peripherals! {
ADC1 <= virtual,
AES <= AES,
APB_SARADC <= APB_SARADC,
ASSIST_DEBUG <= ASSIST_DEBUG,
ATOMIC <= ATOMIC,
BT <= virtual,
DMA <= DMA,
DS <= DS,
ECC <= ECC,
@ -37,11 +38,13 @@ crate::peripherals! {
HP_SYS <= HP_SYS,
I2C0 <= I2C0,
I2S0 <= I2S0,
IEEE802154 <= virtual,
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
INTPRI <= INTPRI,
IO_MUX <= IO_MUX,
LEDC <= LEDC,
LPWR <= LP_CLKRST,
LP_CORE <= virtual,
LP_PERI <= LP_PERI,
LP_ANA <= LP_ANA,
LP_AON <= LP_AON,
@ -70,7 +73,6 @@ crate::peripherals! {
SPI0 <= SPI0,
SPI1 <= SPI1,
SPI2 <= SPI2,
// SYSTEM is derived from PCR
SYSTEM <= PCR,
SYSTIMER <= SYSTIMER,
TEE <= TEE,
@ -83,10 +85,5 @@ crate::peripherals! {
UART1 <= UART1,
UHCI0 <= UHCI0,
USB_DEVICE <= USB_DEVICE,
// Virtual peripherals:
BT <= virtual,
IEEE802154 <= virtual,
LP_CORE <= virtual,
WIFI <= virtual,
}

View File

@ -20,9 +20,10 @@ pub(crate) use self::peripherals::*;
// peripheral (no `PSRAM`, `RADIO`, etc. peripheral in the PACs), so we're
// creating "virtual peripherals" for them.
crate::peripherals! {
ADC1 <= virtual,
AES <= AES,
APB_SARADC <= APB_SARADC,
ASSIST_DEBUG <= ASSIST_DEBUG,
BT <= virtual,
DMA <= DMA,
DS <= DS,
ECC <= ECC,
@ -35,6 +36,7 @@ crate::peripherals! {
I2C0 <= I2C0,
I2C1 <= I2C1,
I2S0 <= I2S0,
IEEE802154 <= virtual,
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
INTPRI <= INTPRI,
IO_MUX <= IO_MUX,
@ -63,7 +65,6 @@ crate::peripherals! {
SPI0 <= SPI0,
SPI1 <= SPI1,
SPI2 <= SPI2,
// SYSTEM is derived from PCR:
SYSTEM <= PCR,
SYSTIMER <= SYSTIMER,
TEE <= TEE,
@ -75,8 +76,4 @@ crate::peripherals! {
UART1 <= UART1,
UHCI0 <= UHCI0,
USB_DEVICE <= USB_DEVICE,
// Virtual peripherals:
BT <= virtual,
IEEE802154 <= virtual,
}

View File

@ -20,8 +20,11 @@ pub(crate) use self::peripherals::*;
// peripheral (no `PSRAM`, `RADIO`, etc. peripheral in the PACs), so we're
// creating "virtual peripherals" for them.
crate::peripherals! {
ADC1 <= virtual,
ADC2 <= virtual,
AES <= AES,
APB_SARADC <= APB_SARADC,
DAC1 <= virtual,
DAC2 <= virtual,
DEDICATED_GPIO <= DEDICATED_GPIO,
DS <= DS,
EFUSE <= EFUSE,
@ -38,12 +41,12 @@ crate::peripherals! {
LPWR <= RTC_CNTL,
PCNT <= PCNT,
PMS <= PMS,
PSRAM <= virtual,
RMT <= RMT,
RNG <= RNG,
RSA <= RSA,
RTC_IO <= RTC_IO,
RTC_I2C <= RTC_I2C,
SENS <= SENS,
SHA <= SHA,
SPI0 <= SPI0,
SPI1 <= SPI1,
@ -59,12 +62,9 @@ crate::peripherals! {
UART0 <= UART0,
UART1 <= UART1,
UHCI0 <= UHCI0,
ULP_RISCV_CORE <= virtual,
USB0 <= USB0,
USB_WRAP <= USB_WRAP,
XTS_AES <= XTS_AES,
// Virtual peripherals:
PSRAM <= virtual,
ULP_RISCV_CORE <= virtual,
WIFI <= virtual,
XTS_AES <= XTS_AES,
}

View File

@ -20,10 +20,12 @@ pub(crate) use self::peripherals::*;
// peripheral (no `PSRAM`, `RADIO`, etc. peripheral in the PACs), so we're
// creating "virtual peripherals" for them.
crate::peripherals! {
ADC1 <= virtual,
ADC2 <= virtual,
AES <= AES,
APB_CTRL <= APB_CTRL,
APB_SARADC <= APB_SARADC,
ASSIST_DEBUG <= ASSIST_DEBUG,
BT <= virtual,
DMA <= DMA,
DS <= DS,
EFUSE <= EFUSE,
@ -43,6 +45,7 @@ crate::peripherals! {
LPWR <= RTC_CNTL,
PCNT <= PCNT,
PERI_BACKUP <= PERI_BACKUP,
PSRAM <= virtual,
MCPWM0 <= MCPWM0,
MCPWM1 <= MCPWM1,
RMT <= RMT,
@ -50,7 +53,6 @@ crate::peripherals! {
RSA <= RSA,
RTC_I2C <= RTC_I2C,
RTC_IO <= RTC_IO,
SENS <= SENS,
SENSITIVE <= SENSITIVE,
SHA <= SHA,
SPI0 <= SPI0,
@ -67,15 +69,11 @@ crate::peripherals! {
UART2 <= UART2,
UHCI0 <= UHCI0,
UHCI1 <= UHCI1,
ULP_RISCV_CORE <= virtual,
USB0 <= USB0,
USB_DEVICE <= USB_DEVICE,
USB_WRAP <= USB_WRAP,
WCL <= WCL,
XTS_AES <= XTS_AES,
// Virtual peripherals:
BT <= virtual,
PSRAM <= virtual,
ULP_RISCV_CORE <= virtual,
WIFI <= virtual,
XTS_AES <= XTS_AES,
}

View File

@ -6,10 +6,10 @@
#![no_main]
use esp32_hal::{
adc::{AdcConfig, Attenuation, ADC, ADC2},
adc::{AdcConfig, Attenuation, ADC},
clock::ClockControl,
gpio::IO,
peripherals::Peripherals,
peripherals::{Peripherals, ADC2},
prelude::*,
Delay,
};
@ -25,12 +25,10 @@ fn main() -> ! {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// Create ADC instances
let analog = peripherals.SENS.split();
let mut adc2_config = AdcConfig::new();
let mut pin25 =
adc2_config.enable_pin(io.pins.gpio25.into_analog(), Attenuation::Attenuation11dB);
let mut adc2 = ADC::<ADC2>::adc(analog.adc2, adc2_config).unwrap();
let mut adc2 = ADC::<ADC2>::adc(peripherals.ADC2, adc2_config).unwrap();
let mut delay = Delay::new(&clocks);

View File

@ -5,7 +5,14 @@
#![no_std]
#![no_main]
use esp32_hal::{clock::ClockControl, dac, gpio::IO, peripherals::Peripherals, prelude::*, Delay};
use esp32_hal::{
clock::ClockControl,
dac::{DAC1, DAC2},
gpio::IO,
peripherals::Peripherals,
prelude::*,
Delay,
};
use esp_backtrace as _;
#[entry]
@ -19,9 +26,8 @@ fn main() -> ! {
let pin26 = io.pins.gpio26.into_analog();
// Create DAC instances
let analog = peripherals.SENS.split();
let mut dac1 = dac::DAC1::dac(analog.dac1, pin25).unwrap();
let mut dac2 = dac::DAC2::dac(analog.dac2, pin26).unwrap();
let mut dac1 = DAC1::new(peripherals.DAC1, pin25);
let mut dac2 = DAC2::new(peripherals.DAC2, pin26);
let mut delay = Delay::new(&clocks);

View File

@ -6,10 +6,10 @@
#![no_main]
use esp32c2_hal::{
adc::{AdcConfig, Attenuation, ADC, ADC1},
adc::{AdcConfig, Attenuation, ADC},
clock::ClockControl,
gpio::IO,
peripherals::Peripherals,
peripherals::{Peripherals, ADC1},
prelude::*,
Delay,
};
@ -25,13 +25,9 @@ fn main() -> ! {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// Create ADC instances
let analog = peripherals.APB_SARADC.split();
let mut adc1_config = AdcConfig::new();
let mut pin = adc1_config.enable_pin(io.pins.gpio2.into_analog(), Attenuation::Attenuation11dB);
let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
let mut adc1 = ADC::<ADC1>::adc(peripherals.ADC1, adc1_config).unwrap();
let mut delay = Delay::new(&clocks);

View File

@ -7,10 +7,10 @@
use esp32c2_hal::{
adc,
adc::{AdcConfig, Attenuation, ADC, ADC1},
adc::{AdcConfig, Attenuation, ADC},
clock::ClockControl,
gpio::IO,
peripherals::Peripherals,
peripherals::{Peripherals, ADC1},
prelude::*,
Delay,
};
@ -26,12 +26,6 @@ fn main() -> ! {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// Create ADC instances
let analog = peripherals.APB_SARADC.split();
let mut adc1_config = AdcConfig::new();
let atten = Attenuation::Attenuation11dB;
// You can try any of the following calibration methods by uncommenting
// them. Note that only AdcCalLine returns readings in mV; the other two
// return raw readings in some unspecified scale.
@ -40,9 +34,12 @@ fn main() -> ! {
// type AdcCal = adc::AdcCalBasic<ADC1>;
type AdcCal = adc::AdcCalLine<ADC1>;
let mut pin = adc1_config.enable_pin_with_cal::<_, AdcCal>(io.pins.gpio2.into_analog(), atten);
let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
let mut adc1_config = AdcConfig::new();
let mut pin = adc1_config.enable_pin_with_cal::<_, AdcCal>(
io.pins.gpio2.into_analog(),
Attenuation::Attenuation11dB,
);
let mut adc1 = ADC::<ADC1>::adc(peripherals.ADC1, adc1_config).unwrap();
let mut delay = Delay::new(&clocks);

View File

@ -6,10 +6,10 @@
#![no_main]
use esp32c3_hal::{
adc::{AdcConfig, Attenuation, ADC, ADC1},
adc::{AdcConfig, Attenuation, ADC},
clock::ClockControl,
gpio::IO,
peripherals::Peripherals,
peripherals::{Peripherals, ADC1},
prelude::*,
Delay,
};
@ -25,13 +25,9 @@ fn main() -> ! {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// Create ADC instances
let analog = peripherals.APB_SARADC.split();
let mut adc1_config = AdcConfig::new();
let mut pin = adc1_config.enable_pin(io.pins.gpio2.into_analog(), Attenuation::Attenuation11dB);
let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
let mut adc1 = ADC::<ADC1>::adc(peripherals.ADC1, adc1_config).unwrap();
let mut delay = Delay::new(&clocks);

View File

@ -7,10 +7,10 @@
use esp32c3_hal::{
adc,
adc::{AdcConfig, Attenuation, ADC, ADC1},
adc::{AdcConfig, Attenuation, ADC},
clock::ClockControl,
gpio::IO,
peripherals::Peripherals,
peripherals::{Peripherals, ADC1},
prelude::*,
Delay,
};
@ -26,12 +26,6 @@ fn main() -> ! {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// Create ADC instances
let analog = peripherals.APB_SARADC.split();
let mut adc1_config = AdcConfig::new();
let atten = Attenuation::Attenuation11dB;
// You can try any of the following calibration methods by uncommenting them.
// Note that only AdcCalLine and AdcCalCurve return readings in mV; the other
// two return raw readings in some unspecified scale.
@ -41,9 +35,12 @@ fn main() -> ! {
// type AdcCal = adc::AdcCalLine<ADC1>;
type AdcCal = adc::AdcCalCurve<ADC1>;
let mut pin = adc1_config.enable_pin_with_cal::<_, AdcCal>(io.pins.gpio2.into_analog(), atten);
let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
let mut adc1_config = AdcConfig::new();
let mut pin = adc1_config.enable_pin_with_cal::<_, AdcCal>(
io.pins.gpio2.into_analog(),
Attenuation::Attenuation11dB,
);
let mut adc1 = ADC::<ADC1>::adc(peripherals.ADC1, adc1_config).unwrap();
let mut delay = Delay::new(&clocks);

View File

@ -6,10 +6,10 @@
#![no_main]
use esp32c6_hal::{
adc::{AdcConfig, Attenuation, ADC, ADC1},
adc::{AdcConfig, Attenuation, ADC},
clock::ClockControl,
gpio::IO,
peripherals::Peripherals,
peripherals::{Peripherals, ADC1},
prelude::*,
Delay,
};
@ -25,13 +25,9 @@ fn main() -> ! {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// Create ADC instances
let analog = peripherals.APB_SARADC.split();
let mut adc1_config = AdcConfig::new();
let mut pin = adc1_config.enable_pin(io.pins.gpio2.into_analog(), Attenuation::Attenuation11dB);
let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
let mut adc1 = ADC::<ADC1>::adc(peripherals.ADC1, adc1_config).unwrap();
let mut delay = Delay::new(&clocks);

View File

@ -7,10 +7,10 @@
use esp32c6_hal::{
adc,
adc::{AdcConfig, Attenuation, ADC, ADC1},
adc::{AdcConfig, Attenuation, ADC},
clock::ClockControl,
gpio::IO,
peripherals::Peripherals,
peripherals::{Peripherals, ADC1},
prelude::*,
Delay,
};
@ -26,12 +26,6 @@ fn main() -> ! {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// Create ADC instances
let analog = peripherals.APB_SARADC.split();
let mut adc1_config = AdcConfig::new();
let atten = Attenuation::Attenuation11dB;
// You can try any of the following calibration methods by uncommenting them.
// Note that only AdcCalLine and AdcCalCurve return readings in mV; the other
// two return raw readings in some unspecified scale.
@ -41,9 +35,12 @@ fn main() -> ! {
// type AdcCal = adc::AdcCalLine<ADC1>;
type AdcCal = adc::AdcCalCurve<ADC1>;
let mut pin = adc1_config.enable_pin_with_cal::<_, AdcCal>(io.pins.gpio2.into_analog(), atten);
let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
let mut adc1_config = AdcConfig::new();
let mut pin = adc1_config.enable_pin_with_cal::<_, AdcCal>(
io.pins.gpio2.into_analog(),
Attenuation::Attenuation11dB,
);
let mut adc1 = ADC::<ADC1>::adc(peripherals.ADC1, adc1_config).unwrap();
let mut delay = Delay::new(&clocks);

View File

@ -6,10 +6,10 @@
#![no_main]
use esp32h2_hal::{
adc::{AdcConfig, Attenuation, ADC, ADC1},
adc::{AdcConfig, Attenuation, ADC},
clock::ClockControl,
gpio::IO,
peripherals::Peripherals,
peripherals::{Peripherals, ADC1},
prelude::*,
Delay,
};
@ -25,13 +25,9 @@ fn main() -> ! {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// Create ADC instances
let analog = peripherals.APB_SARADC.split();
let mut adc1_config = AdcConfig::new();
let mut pin = adc1_config.enable_pin(io.pins.gpio2.into_analog(), Attenuation::Attenuation11dB);
let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
let mut adc1 = ADC::<ADC1>::adc(peripherals.ADC1, adc1_config).unwrap();
let mut delay = Delay::new(&clocks);

View File

@ -6,10 +6,10 @@
#![no_main]
use esp32s2_hal::{
adc::{AdcConfig, Attenuation, ADC, ADC1},
adc::{AdcConfig, Attenuation, ADC},
clock::ClockControl,
gpio::IO,
peripherals::Peripherals,
peripherals::{Peripherals, ADC1},
prelude::*,
Delay,
};
@ -25,14 +25,10 @@ fn main() -> ! {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// Create ADC instances
let analog = peripherals.SENS.split();
let mut adc1_config = AdcConfig::new();
let mut pin3 =
adc1_config.enable_pin(io.pins.gpio3.into_analog(), Attenuation::Attenuation11dB);
let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
let mut adc1 = ADC::<ADC1>::adc(peripherals.ADC1, adc1_config).unwrap();
let mut delay = Delay::new(&clocks);

View File

@ -7,7 +7,7 @@
use esp32s2_hal::{
clock::ClockControl,
dac,
dac::{DAC1, DAC2},
gpio::IO,
peripherals::Peripherals,
prelude::*,
@ -26,9 +26,8 @@ fn main() -> ! {
let pin18 = io.pins.gpio18.into_analog();
// Create DAC instances
let analog = peripherals.SENS.split();
let mut dac1 = dac::DAC1::dac(analog.dac1, pin17).unwrap();
let mut dac2 = dac::DAC2::dac(analog.dac2, pin18).unwrap();
let mut dac1 = DAC1::new(peripherals.DAC1, pin17);
let mut dac2 = DAC2::new(peripherals.DAC2, pin18);
let mut delay = Delay::new(&clocks);

View File

@ -6,10 +6,10 @@
#![no_main]
use esp32s3_hal::{
adc::{AdcConfig, Attenuation, ADC, ADC1},
adc::{AdcConfig, Attenuation, ADC},
clock::ClockControl,
gpio::IO,
peripherals::Peripherals,
peripherals::{Peripherals, ADC1},
prelude::*,
Delay,
};
@ -25,14 +25,10 @@ fn main() -> ! {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// Create ADC instances
let analog = peripherals.SENS.split();
let mut adc1_config = AdcConfig::new();
let mut pin3 =
adc1_config.enable_pin(io.pins.gpio3.into_analog(), Attenuation::Attenuation11dB);
let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
let mut adc1 = ADC::<ADC1>::adc(peripherals.ADC1, adc1_config).unwrap();
let mut delay = Delay::new(&clocks);

View File

@ -6,10 +6,10 @@
#![no_main]
use esp32s3_hal::{
adc::{self, AdcConfig, Attenuation, ADC, ADC1},
adc::{self, AdcConfig, Attenuation, ADC},
clock::ClockControl,
gpio::IO,
peripherals::Peripherals,
peripherals::{Peripherals, ADC1},
prelude::*,
Delay,
};
@ -25,12 +25,6 @@ fn main() -> ! {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// Create ADC instances
let analog = peripherals.SENS.split();
let mut adc1_config = AdcConfig::new();
let atten = Attenuation::Attenuation11dB;
// You can try any of the following calibration methods by uncommenting them.
// Note that only AdcCalLine and AdcCalCurve return readings in mV; the other
// two return raw readings in some unspecified scale.
@ -40,9 +34,12 @@ fn main() -> ! {
// type AdcCal = adc::AdcCalLine<ADC1>;
type AdcCal = adc::AdcCalCurve<ADC1>;
let mut pin = adc1_config.enable_pin_with_cal::<_, AdcCal>(io.pins.gpio3.into_analog(), atten);
let mut adc1 = ADC::<ADC1>::adc(analog.adc1, adc1_config).unwrap();
let mut adc1_config = AdcConfig::new();
let mut pin = adc1_config.enable_pin_with_cal::<_, AdcCal>(
io.pins.gpio3.into_analog(),
Attenuation::Attenuation11dB,
);
let mut adc1 = ADC::<ADC1>::adc(peripherals.ADC1, adc1_config).unwrap();
let mut delay = Delay::new(&clocks);