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;
}