esp_hal/analog/dac.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
//! # Digital to Analog Converter (DAC)
//!
//! ## Overview
//! Espressif devices usually have multiple DAC channels. Each DAC channel can
//! convert the digital value 0~255 to the analog voltage 0~Vref (The reference
//! voltage 'Vref' here is input from an input pin)
//!
//! The DAC peripheral supports outputting analog signal in the multiple ways.
//!
//! Two 8-bit DAC channels are available.
//!
//! ## Configuration
//! Developers can choose the DAC channel they want to use based on the GPIO
//! pin assignments for each channel.
//!
//! ## Examples
//! ### Write a value to a DAC channel
//! ```rust, no_run
#![doc = crate::before_snippet!()]
//! # use esp_hal::analog::dac::Dac;
//! # use esp_hal::delay::Delay;
//! # use embedded_hal::delay::DelayNs;
#![cfg_attr(esp32, doc = "let dac1_pin = peripherals.GPIO25;")]
#![cfg_attr(esp32s2, doc = "let dac1_pin = peripherals.GPIO17;")]
//! let mut dac1 = Dac::new(peripherals.DAC1, dac1_pin);
//!
//! let mut delay = Delay::new();
//!
//! let mut voltage_dac1 = 200u8;
//!
//! // Change voltage on the pins using write function:
//! loop {
//! voltage_dac1 = voltage_dac1.wrapping_add(1);
//! dac1.write(voltage_dac1);
//!
//! delay.delay_ms(50u32);
//! }
//! # }
//! ```
use crate::{
gpio::{self, AnalogPin},
peripheral::{Peripheral, PeripheralRef},
};
// Only specific pins can be used with each DAC peripheral, and of course
// these pins are different depending on which chip you are using; for this
// reason, we will type alias the pins for ease of use later in this module:
cfg_if::cfg_if! {
if #[cfg(esp32)] {
type Dac1Gpio = gpio::GpioPin<25>;
type Dac2Gpio = gpio::GpioPin<26>;
} else if #[cfg(esp32s2)] {
type Dac1Gpio = gpio::GpioPin<17>;
type Dac2Gpio = gpio::GpioPin<18>;
}
}
/// Digital-to-Analog Converter (DAC) Channel
pub struct Dac<'d, T>
where
T: Instance,
T::Pin: AnalogPin,
{
_inner: PeripheralRef<'d, T>,
}
impl<'d, T> Dac<'d, T>
where
T: Instance,
T::Pin: AnalogPin,
{
/// Construct a new instance of [`Dac`].
pub fn new(dac: impl Peripheral<P = T> + 'd, pin: T::Pin) -> Self {
crate::into_ref!(dac);
// TODO: Revert on drop.
pin.set_analog(crate::private::Internal);
#[cfg(esp32s2)]
crate::peripherals::SENS::regs()
.sar_dac_ctrl1()
.modify(|_, w| w.dac_clkgate_en().set_bit());
T::enable_xpd();
Self { _inner: 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) {
T::set_pad_source();
T::write_byte(value);
}
}
#[doc(hidden)]
pub trait Instance: crate::private::Sealed {
const INDEX: usize;
type Pin;
fn enable_xpd() {
crate::peripherals::RTC_IO::regs()
.pad_dac(Self::INDEX)
.modify(|_, w| w.dac_xpd_force().set_bit().xpd_dac().set_bit());
}
fn set_pad_source() {
crate::peripherals::SENS::regs()
.sar_dac_ctrl2()
.modify(|_, w| w.dac_cw_en(Self::INDEX as u8).clear_bit());
}
fn write_byte(value: u8) {
crate::peripherals::RTC_IO::regs()
.pad_dac(Self::INDEX)
.modify(|_, w| unsafe { w.dac().bits(value) });
}
}
impl Instance for crate::peripherals::DAC1 {
const INDEX: usize = 0;
type Pin = Dac1Gpio;
}
impl Instance for crate::peripherals::DAC2 {
const INDEX: usize = 1;
type Pin = Dac2Gpio;
}