mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-27 04:10:28 +00:00
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:
parent
43f212dc72
commit
f52aa1351c
@ -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
|
||||
|
@ -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,
|
@ -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;
|
||||
}
|
||||
|
@ -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 {}
|
14
esp-hal-common/src/analog/adc/calibration/mod.rs
Normal file
14
esp-hal-common/src/analog/adc/calibration/mod.rs
Normal 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;
|
@ -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
|
||||
|
108
esp-hal-common/src/analog/adc/mod.rs
Normal file
108
esp-hal-common/src/analog/adc/mod.rs
Normal 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>;
|
||||
}
|
@ -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 [
|
||||
|
@ -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),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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: (),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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))]
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user