| 1 | //! Digital to Analog Converter (DAC) |
| 2 | #![macro_use ] |
| 3 | |
| 4 | use core::marker::PhantomData; |
| 5 | |
| 6 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 7 | |
| 8 | use crate::dma::NoDma; |
| 9 | #[cfg (any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] |
| 10 | use crate::pac::dac; |
| 11 | use crate::rcc::{self, RccPeripheral}; |
| 12 | use crate::{peripherals, Peripheral}; |
| 13 | |
| 14 | mod tsel; |
| 15 | pub use tsel::TriggerSel; |
| 16 | |
| 17 | /// Operating mode for DAC channel |
| 18 | #[cfg (any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] |
| 19 | #[derive (Debug, Copy, Clone, Eq, PartialEq)] |
| 20 | #[cfg_attr (feature = "defmt" , derive(defmt::Format))] |
| 21 | pub enum Mode { |
| 22 | /// Normal mode, channel is connected to external pin with buffer enabled. |
| 23 | NormalExternalBuffered, |
| 24 | /// Normal mode, channel is connected to external pin and internal peripherals |
| 25 | /// with buffer enabled. |
| 26 | NormalBothBuffered, |
| 27 | /// Normal mode, channel is connected to external pin with buffer disabled. |
| 28 | NormalExternalUnbuffered, |
| 29 | /// Normal mode, channel is connected to internal peripherals with buffer disabled. |
| 30 | NormalInternalUnbuffered, |
| 31 | /// Sample-and-hold mode, channel is connected to external pin with buffer enabled. |
| 32 | SampleHoldExternalBuffered, |
| 33 | /// Sample-and-hold mode, channel is connected to external pin and internal peripherals |
| 34 | /// with buffer enabled. |
| 35 | SampleHoldBothBuffered, |
| 36 | /// Sample-and-hold mode, channel is connected to external pin and internal peripherals |
| 37 | /// with buffer disabled. |
| 38 | SampleHoldBothUnbuffered, |
| 39 | /// Sample-and-hold mode, channel is connected to internal peripherals with buffer disabled. |
| 40 | SampleHoldInternalUnbuffered, |
| 41 | } |
| 42 | |
| 43 | #[cfg (any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] |
| 44 | impl Mode { |
| 45 | fn mode(&self) -> dac::vals::Mode { |
| 46 | match self { |
| 47 | Mode::NormalExternalBuffered => dac::vals::Mode::NORMAL_EXT_BUFEN, |
| 48 | Mode::NormalBothBuffered => dac::vals::Mode::NORMAL_EXT_INT_BUFEN, |
| 49 | Mode::NormalExternalUnbuffered => dac::vals::Mode::NORMAL_EXT_BUFDIS, |
| 50 | Mode::NormalInternalUnbuffered => dac::vals::Mode::NORMAL_INT_BUFDIS, |
| 51 | Mode::SampleHoldExternalBuffered => dac::vals::Mode::SAMPHOLD_EXT_BUFEN, |
| 52 | Mode::SampleHoldBothBuffered => dac::vals::Mode::SAMPHOLD_EXT_INT_BUFEN, |
| 53 | Mode::SampleHoldBothUnbuffered => dac::vals::Mode::SAMPHOLD_EXT_INT_BUFDIS, |
| 54 | Mode::SampleHoldInternalUnbuffered => dac::vals::Mode::SAMPHOLD_INT_BUFDIS, |
| 55 | } |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | #[derive (Debug, Copy, Clone, Eq, PartialEq)] |
| 60 | #[cfg_attr (feature = "defmt" , derive(defmt::Format))] |
| 61 | /// Single 8 or 12 bit value that can be output by the DAC. |
| 62 | /// |
| 63 | /// 12-bit values outside the permitted range are silently truncated. |
| 64 | pub enum Value { |
| 65 | /// 8 bit value |
| 66 | Bit8(u8), |
| 67 | /// 12 bit value stored in a u16, left-aligned |
| 68 | Bit12Left(u16), |
| 69 | /// 12 bit value stored in a u16, right-aligned |
| 70 | Bit12Right(u16), |
| 71 | } |
| 72 | |
| 73 | #[derive (Debug, Copy, Clone, Eq, PartialEq)] |
| 74 | #[cfg_attr (feature = "defmt" , derive(defmt::Format))] |
| 75 | /// Dual 8 or 12 bit values that can be output by the DAC channels 1 and 2 simultaneously. |
| 76 | /// |
| 77 | /// 12-bit values outside the permitted range are silently truncated. |
| 78 | pub enum DualValue { |
| 79 | /// 8 bit value |
| 80 | Bit8(u8, u8), |
| 81 | /// 12 bit value stored in a u16, left-aligned |
| 82 | Bit12Left(u16, u16), |
| 83 | /// 12 bit value stored in a u16, right-aligned |
| 84 | Bit12Right(u16, u16), |
| 85 | } |
| 86 | |
| 87 | #[derive (Debug, Copy, Clone, Eq, PartialEq)] |
| 88 | #[cfg_attr (feature = "defmt" , derive(defmt::Format))] |
| 89 | /// Array variant of [`Value`]. |
| 90 | pub enum ValueArray<'a> { |
| 91 | /// 8 bit values |
| 92 | Bit8(&'a [u8]), |
| 93 | /// 12 bit value stored in a u16, left-aligned |
| 94 | Bit12Left(&'a [u16]), |
| 95 | /// 12 bit values stored in a u16, right-aligned |
| 96 | Bit12Right(&'a [u16]), |
| 97 | } |
| 98 | |
| 99 | /// Driver for a single DAC channel. |
| 100 | /// |
| 101 | /// If you want to use both channels, either together or independently, |
| 102 | /// create a [`Dac`] first and use it to access each channel. |
| 103 | pub struct DacChannel<'d, T: Instance, const N: u8, DMA = NoDma> { |
| 104 | phantom: PhantomData<&'d mut T>, |
| 105 | #[allow (unused)] |
| 106 | dma: PeripheralRef<'d, DMA>, |
| 107 | } |
| 108 | |
| 109 | /// DAC channel 1 type alias. |
| 110 | pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>; |
| 111 | /// DAC channel 2 type alias. |
| 112 | pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>; |
| 113 | |
| 114 | impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { |
| 115 | const IDX: usize = (N - 1) as usize; |
| 116 | |
| 117 | /// Create a new `DacChannel` instance, consuming the underlying DAC peripheral. |
| 118 | /// |
| 119 | /// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument. |
| 120 | /// |
| 121 | /// The channel is enabled on creation and begin to drive the output pin. |
| 122 | /// Note that some methods, such as `set_trigger()` and `set_mode()`, will |
| 123 | /// disable the channel; you must re-enable it with `enable()`. |
| 124 | /// |
| 125 | /// By default, triggering is disabled, but it can be enabled using |
| 126 | /// [`DacChannel::set_trigger()`]. |
| 127 | pub fn new( |
| 128 | _peri: impl Peripheral<P = T> + 'd, |
| 129 | dma: impl Peripheral<P = DMA> + 'd, |
| 130 | pin: impl Peripheral<P = impl DacPin<T, N> + crate::gpio::Pin> + 'd, |
| 131 | ) -> Self { |
| 132 | into_ref!(dma, pin); |
| 133 | pin.set_as_analog(); |
| 134 | rcc::enable_and_reset::<T>(); |
| 135 | let mut dac = Self { |
| 136 | phantom: PhantomData, |
| 137 | dma, |
| 138 | }; |
| 139 | #[cfg (any(dac_v5, dac_v6, dac_v7))] |
| 140 | dac.set_hfsel(); |
| 141 | dac.enable(); |
| 142 | dac |
| 143 | } |
| 144 | |
| 145 | /// Create a new `DacChannel` instance where the external output pin is not used, |
| 146 | /// so the DAC can only be used to generate internal signals. |
| 147 | /// The GPIO pin is therefore available to be used for other functions. |
| 148 | /// |
| 149 | /// The channel is set to [`Mode::NormalInternalUnbuffered`] and enabled on creation. |
| 150 | /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the |
| 151 | /// channel; you must re-enable it with `enable()`. |
| 152 | /// |
| 153 | /// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument. |
| 154 | /// |
| 155 | /// By default, triggering is disabled, but it can be enabled using |
| 156 | /// [`DacChannel::set_trigger()`]. |
| 157 | #[cfg (all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] |
| 158 | pub fn new_internal(_peri: impl Peripheral<P = T> + 'd, dma: impl Peripheral<P = DMA> + 'd) -> Self { |
| 159 | into_ref!(dma); |
| 160 | rcc::enable_and_reset::<T>(); |
| 161 | let mut dac = Self { |
| 162 | phantom: PhantomData, |
| 163 | dma, |
| 164 | }; |
| 165 | #[cfg (any(dac_v5, dac_v6, dac_v7))] |
| 166 | dac.set_hfsel(); |
| 167 | dac.set_mode(Mode::NormalInternalUnbuffered); |
| 168 | dac.enable(); |
| 169 | dac |
| 170 | } |
| 171 | |
| 172 | /// Enable or disable this channel. |
| 173 | pub fn set_enable(&mut self, on: bool) { |
| 174 | critical_section::with(|_| { |
| 175 | T::regs().cr().modify(|reg| { |
| 176 | reg.set_en(Self::IDX, on); |
| 177 | }); |
| 178 | }); |
| 179 | } |
| 180 | |
| 181 | /// Enable this channel. |
| 182 | pub fn enable(&mut self) { |
| 183 | self.set_enable(true) |
| 184 | } |
| 185 | |
| 186 | /// Disable this channel. |
| 187 | pub fn disable(&mut self) { |
| 188 | self.set_enable(false) |
| 189 | } |
| 190 | |
| 191 | /// Set the trigger source for this channel. |
| 192 | /// |
| 193 | /// This method disables the channel, so you may need to re-enable afterwards. |
| 194 | pub fn set_trigger(&mut self, source: TriggerSel) { |
| 195 | critical_section::with(|_| { |
| 196 | T::regs().cr().modify(|reg| { |
| 197 | reg.set_en(Self::IDX, false); |
| 198 | reg.set_tsel(Self::IDX, source as u8); |
| 199 | }); |
| 200 | }); |
| 201 | } |
| 202 | |
| 203 | /// Enable or disable triggering for this channel. |
| 204 | pub fn set_triggering(&mut self, on: bool) { |
| 205 | critical_section::with(|_| { |
| 206 | T::regs().cr().modify(|reg| { |
| 207 | reg.set_ten(Self::IDX, on); |
| 208 | }); |
| 209 | }); |
| 210 | } |
| 211 | |
| 212 | /// Software trigger this channel. |
| 213 | pub fn trigger(&mut self) { |
| 214 | T::regs().swtrigr().write(|reg| { |
| 215 | reg.set_swtrig(Self::IDX, true); |
| 216 | }); |
| 217 | } |
| 218 | |
| 219 | /// Set mode of this channel. |
| 220 | /// |
| 221 | /// This method disables the channel, so you may need to re-enable afterwards. |
| 222 | #[cfg (any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] |
| 223 | pub fn set_mode(&mut self, mode: Mode) { |
| 224 | critical_section::with(|_| { |
| 225 | T::regs().cr().modify(|reg| { |
| 226 | reg.set_en(Self::IDX, false); |
| 227 | }); |
| 228 | T::regs().mcr().modify(|reg| { |
| 229 | reg.set_mode(Self::IDX, mode.mode()); |
| 230 | }); |
| 231 | }); |
| 232 | } |
| 233 | |
| 234 | /// Write a new value to this channel. |
| 235 | /// |
| 236 | /// If triggering is not enabled, the new value is immediately output; otherwise, |
| 237 | /// it will be output after the next trigger. |
| 238 | pub fn set(&mut self, value: Value) { |
| 239 | match value { |
| 240 | Value::Bit8(v) => T::regs().dhr8r(Self::IDX).write(|reg| reg.set_dhr(v)), |
| 241 | Value::Bit12Left(v) => T::regs().dhr12l(Self::IDX).write(|reg| reg.set_dhr(v)), |
| 242 | Value::Bit12Right(v) => T::regs().dhr12r(Self::IDX).write(|reg| reg.set_dhr(v)), |
| 243 | } |
| 244 | } |
| 245 | |
| 246 | /// Read the current output value of the DAC. |
| 247 | pub fn read(&self) -> u16 { |
| 248 | T::regs().dor(Self::IDX).read().dor() |
| 249 | } |
| 250 | |
| 251 | /// Set HFSEL as appropriate for the current peripheral clock frequency. |
| 252 | #[cfg (dac_v5)] |
| 253 | fn set_hfsel(&mut self) { |
| 254 | if T::frequency() >= crate::time::mhz(80) { |
| 255 | critical_section::with(|_| { |
| 256 | T::regs().cr().modify(|reg| { |
| 257 | reg.set_hfsel(true); |
| 258 | }); |
| 259 | }); |
| 260 | } |
| 261 | } |
| 262 | |
| 263 | /// Set HFSEL as appropriate for the current peripheral clock frequency. |
| 264 | #[cfg (any(dac_v6, dac_v7))] |
| 265 | fn set_hfsel(&mut self) { |
| 266 | if T::frequency() >= crate::time::mhz(160) { |
| 267 | critical_section::with(|_| { |
| 268 | T::regs().mcr().modify(|reg| { |
| 269 | reg.set_hfsel(0b10); |
| 270 | }); |
| 271 | }); |
| 272 | } else if T::frequency() >= crate::time::mhz(80) { |
| 273 | critical_section::with(|_| { |
| 274 | T::regs().mcr().modify(|reg| { |
| 275 | reg.set_hfsel(0b01); |
| 276 | }); |
| 277 | }); |
| 278 | } |
| 279 | } |
| 280 | } |
| 281 | |
| 282 | macro_rules! impl_dma_methods { |
| 283 | ($n:literal, $trait:ident) => { |
| 284 | impl<'d, T: Instance, DMA> DacChannel<'d, T, $n, DMA> |
| 285 | where |
| 286 | DMA: $trait<T>, |
| 287 | { |
| 288 | /// Write `data` to this channel via DMA. |
| 289 | /// |
| 290 | /// To prevent delays or glitches when outputing a periodic waveform, the `circular` |
| 291 | /// flag can be set. This configures a circular DMA transfer that continually outputs |
| 292 | /// `data`. Note that for performance reasons in circular mode the transfer-complete |
| 293 | /// interrupt is disabled. |
| 294 | #[cfg(not(gpdma))] |
| 295 | pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) { |
| 296 | // Enable DAC and DMA |
| 297 | T::regs().cr().modify(|w| { |
| 298 | w.set_en(Self::IDX, true); |
| 299 | w.set_dmaen(Self::IDX, true); |
| 300 | }); |
| 301 | |
| 302 | let tx_request = self.dma.request(); |
| 303 | let dma_channel = &mut self.dma; |
| 304 | |
| 305 | let tx_options = crate::dma::TransferOptions { |
| 306 | circular, |
| 307 | half_transfer_ir: false, |
| 308 | complete_transfer_ir: !circular, |
| 309 | ..Default::default() |
| 310 | }; |
| 311 | |
| 312 | // Initiate the correct type of DMA transfer depending on what data is passed |
| 313 | let tx_f = match data { |
| 314 | ValueArray::Bit8(buf) => unsafe { |
| 315 | crate::dma::Transfer::new_write( |
| 316 | dma_channel, |
| 317 | tx_request, |
| 318 | buf, |
| 319 | T::regs().dhr8r(Self::IDX).as_ptr() as *mut u8, |
| 320 | tx_options, |
| 321 | ) |
| 322 | }, |
| 323 | ValueArray::Bit12Left(buf) => unsafe { |
| 324 | crate::dma::Transfer::new_write( |
| 325 | dma_channel, |
| 326 | tx_request, |
| 327 | buf, |
| 328 | T::regs().dhr12l(Self::IDX).as_ptr() as *mut u16, |
| 329 | tx_options, |
| 330 | ) |
| 331 | }, |
| 332 | ValueArray::Bit12Right(buf) => unsafe { |
| 333 | crate::dma::Transfer::new_write( |
| 334 | dma_channel, |
| 335 | tx_request, |
| 336 | buf, |
| 337 | T::regs().dhr12r(Self::IDX).as_ptr() as *mut u16, |
| 338 | tx_options, |
| 339 | ) |
| 340 | }, |
| 341 | }; |
| 342 | |
| 343 | tx_f.await; |
| 344 | |
| 345 | T::regs().cr().modify(|w| { |
| 346 | w.set_en(Self::IDX, false); |
| 347 | w.set_dmaen(Self::IDX, false); |
| 348 | }); |
| 349 | } |
| 350 | } |
| 351 | }; |
| 352 | } |
| 353 | |
| 354 | impl_dma_methods!(1, DacDma1); |
| 355 | impl_dma_methods!(2, DacDma2); |
| 356 | |
| 357 | impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> { |
| 358 | fn drop(&mut self) { |
| 359 | rcc::disable::<T>(); |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | /// DAC driver. |
| 364 | /// |
| 365 | /// Use this struct when you want to use both channels, either together or independently. |
| 366 | /// |
| 367 | /// # Example |
| 368 | /// |
| 369 | /// ```ignore |
| 370 | /// // Pins may need to be changed for your specific device. |
| 371 | /// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, NoDma, NoDma, p.PA4, p.PA5).split(); |
| 372 | /// ``` |
| 373 | pub struct Dac<'d, T: Instance, DMACh1 = NoDma, DMACh2 = NoDma> { |
| 374 | ch1: DacChannel<'d, T, 1, DMACh1>, |
| 375 | ch2: DacChannel<'d, T, 2, DMACh2>, |
| 376 | } |
| 377 | |
| 378 | impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { |
| 379 | /// Create a new `Dac` instance, consuming the underlying DAC peripheral. |
| 380 | /// |
| 381 | /// This struct allows you to access both channels of the DAC, where available. You can either |
| 382 | /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use |
| 383 | /// the two channels together. |
| 384 | /// |
| 385 | /// The channels are enabled on creation and begin to drive their output pins. |
| 386 | /// Note that some methods, such as `set_trigger()` and `set_mode()`, will |
| 387 | /// disable the channel; you must re-enable them with `enable()`. |
| 388 | /// |
| 389 | /// By default, triggering is disabled, but it can be enabled using the `set_trigger()` |
| 390 | /// method on the underlying channels. |
| 391 | pub fn new( |
| 392 | _peri: impl Peripheral<P = T> + 'd, |
| 393 | dma_ch1: impl Peripheral<P = DMACh1> + 'd, |
| 394 | dma_ch2: impl Peripheral<P = DMACh2> + 'd, |
| 395 | pin_ch1: impl Peripheral<P = impl DacPin<T, 1> + crate::gpio::Pin> + 'd, |
| 396 | pin_ch2: impl Peripheral<P = impl DacPin<T, 2> + crate::gpio::Pin> + 'd, |
| 397 | ) -> Self { |
| 398 | into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2); |
| 399 | pin_ch1.set_as_analog(); |
| 400 | pin_ch2.set_as_analog(); |
| 401 | |
| 402 | // Enable twice to increment the DAC refcount for each channel. |
| 403 | rcc::enable_and_reset::<T>(); |
| 404 | rcc::enable_and_reset::<T>(); |
| 405 | |
| 406 | let mut ch1 = DacCh1 { |
| 407 | phantom: PhantomData, |
| 408 | dma: dma_ch1, |
| 409 | }; |
| 410 | #[cfg (any(dac_v5, dac_v6, dac_v7))] |
| 411 | ch1.set_hfsel(); |
| 412 | ch1.enable(); |
| 413 | |
| 414 | let mut ch2 = DacCh2 { |
| 415 | phantom: PhantomData, |
| 416 | dma: dma_ch2, |
| 417 | }; |
| 418 | #[cfg (any(dac_v5, dac_v6, dac_v7))] |
| 419 | ch2.set_hfsel(); |
| 420 | ch2.enable(); |
| 421 | |
| 422 | Self { ch1, ch2 } |
| 423 | } |
| 424 | |
| 425 | /// Create a new `Dac` instance where the external output pins are not used, |
| 426 | /// so the DAC can only be used to generate internal signals but the GPIO |
| 427 | /// pins remain available for other functions. |
| 428 | /// |
| 429 | /// This struct allows you to access both channels of the DAC, where available. You can either |
| 430 | /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use the two |
| 431 | /// channels together. |
| 432 | /// |
| 433 | /// The channels are set to [`Mode::NormalInternalUnbuffered`] and enabled on creation. |
| 434 | /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the |
| 435 | /// channel; you must re-enable them with `enable()`. |
| 436 | /// |
| 437 | /// By default, triggering is disabled, but it can be enabled using the `set_trigger()` |
| 438 | /// method on the underlying channels. |
| 439 | #[cfg (all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] |
| 440 | pub fn new_internal( |
| 441 | _peri: impl Peripheral<P = T> + 'd, |
| 442 | dma_ch1: impl Peripheral<P = DMACh1> + 'd, |
| 443 | dma_ch2: impl Peripheral<P = DMACh2> + 'd, |
| 444 | ) -> Self { |
| 445 | into_ref!(dma_ch1, dma_ch2); |
| 446 | // Enable twice to increment the DAC refcount for each channel. |
| 447 | rcc::enable_and_reset::<T>(); |
| 448 | rcc::enable_and_reset::<T>(); |
| 449 | |
| 450 | let mut ch1 = DacCh1 { |
| 451 | phantom: PhantomData, |
| 452 | dma: dma_ch1, |
| 453 | }; |
| 454 | #[cfg (any(dac_v5, dac_v6, dac_v7))] |
| 455 | ch1.set_hfsel(); |
| 456 | ch1.set_mode(Mode::NormalInternalUnbuffered); |
| 457 | ch1.enable(); |
| 458 | |
| 459 | let mut ch2 = DacCh2 { |
| 460 | phantom: PhantomData, |
| 461 | dma: dma_ch2, |
| 462 | }; |
| 463 | #[cfg (any(dac_v5, dac_v6, dac_v7))] |
| 464 | ch2.set_hfsel(); |
| 465 | ch2.set_mode(Mode::NormalInternalUnbuffered); |
| 466 | ch2.enable(); |
| 467 | |
| 468 | Self { ch1, ch2 } |
| 469 | } |
| 470 | |
| 471 | /// Split this `Dac` into separate channels. |
| 472 | /// |
| 473 | /// You can access and move the channels around separately after splitting. |
| 474 | pub fn split(self) -> (DacCh1<'d, T, DMACh1>, DacCh2<'d, T, DMACh2>) { |
| 475 | (self.ch1, self.ch2) |
| 476 | } |
| 477 | |
| 478 | /// Temporarily access channel 1. |
| 479 | pub fn ch1(&mut self) -> &mut DacCh1<'d, T, DMACh1> { |
| 480 | &mut self.ch1 |
| 481 | } |
| 482 | |
| 483 | /// Temporarily access channel 2. |
| 484 | pub fn ch2(&mut self) -> &mut DacCh2<'d, T, DMACh2> { |
| 485 | &mut self.ch2 |
| 486 | } |
| 487 | |
| 488 | /// Simultaneously update channels 1 and 2 with a new value. |
| 489 | /// |
| 490 | /// If triggering is not enabled, the new values are immediately output; |
| 491 | /// otherwise, they will be output after the next trigger. |
| 492 | pub fn set(&mut self, values: DualValue) { |
| 493 | match values { |
| 494 | DualValue::Bit8(v1, v2) => T::regs().dhr8rd().write(|reg| { |
| 495 | reg.set_dhr(0, v1); |
| 496 | reg.set_dhr(1, v2); |
| 497 | }), |
| 498 | DualValue::Bit12Left(v1, v2) => T::regs().dhr12ld().write(|reg| { |
| 499 | reg.set_dhr(0, v1); |
| 500 | reg.set_dhr(1, v2); |
| 501 | }), |
| 502 | DualValue::Bit12Right(v1, v2) => T::regs().dhr12rd().write(|reg| { |
| 503 | reg.set_dhr(0, v1); |
| 504 | reg.set_dhr(1, v2); |
| 505 | }), |
| 506 | } |
| 507 | } |
| 508 | } |
| 509 | |
| 510 | trait SealedInstance { |
| 511 | fn regs() -> crate::pac::dac::Dac; |
| 512 | } |
| 513 | |
| 514 | /// DAC instance. |
| 515 | #[allow (private_bounds)] |
| 516 | pub trait Instance: SealedInstance + RccPeripheral + 'static {} |
| 517 | dma_trait!(DacDma1, Instance); |
| 518 | dma_trait!(DacDma2, Instance); |
| 519 | |
| 520 | /// Marks a pin that can be used with the DAC |
| 521 | pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {} |
| 522 | |
| 523 | foreach_peripheral!( |
| 524 | (dac, $inst:ident) => { |
| 525 | impl crate::dac::SealedInstance for peripherals::$inst { |
| 526 | fn regs() -> crate::pac::dac::Dac { |
| 527 | crate::pac::$inst |
| 528 | } |
| 529 | } |
| 530 | |
| 531 | impl crate::dac::Instance for peripherals::$inst {} |
| 532 | }; |
| 533 | ); |
| 534 | |
| 535 | macro_rules! impl_dac_pin { |
| 536 | ($inst:ident, $pin:ident, $ch:expr) => { |
| 537 | impl crate::dac::DacPin<peripherals::$inst, $ch> for crate::peripherals::$pin {} |
| 538 | }; |
| 539 | } |
| 540 | |