sam3_hal/dacc/
mod.rs

1//! # Functional description of the DACC
2//!
3//! Mostly pages 1358-1359 of the datasheet verbatim, though I have taken some liberties by way of
4//! rephrasing some things so they make a bit more sense to me.
5//!
6//!
7//! ## Digital-to-Analog Conversion
8//!
9//! The DACC uses the master clock (MCK) divided by two to perform coversions. This clock is named
10//! DACC Clock. Once a conversion starts, the DACC takes 25 clock periods to provide the analog
11//! result on the selected analog output.
12//!
13//!
14//! ## Conversion Results
15//!
16//! When a conversion is completed, the resulting analog value is available at the selected DACC
17//! channel output and the EOC bit in the DACC Interrupt Status Register is set. Reading the
18//! `DACC_ISR` clears the EOC bit.
19//!
20//!
21//! ## Conversion triggers
22//!
23//! In free running mode, conversion starts as soon as at least one channel is enabled and data is
24//! written in the DACC Conversion Data Register. Then 25 DACC Clock periods later, the converted
25//! data is available at the corresponding analog output as stated above.
26//!
27//! In external trigger mode, the conversion waits for a rising edge on the selected trigger to
28//! begin.
29//!
30//! **WARNING:** Disabling thee external trigger mode automatically sets the DACC in free running
31//! mode.
32//!
33//!
34//! ## Conversion FIFO
35//!
36//! A 4 half-word FIFO is used to handle the data to be converted.
37//!
38//! As long as the `TXRDY` flag in the DACC Interrupt Status Register is active, the DAC Controller
39//! is ready to accept conversion requests by writing data into the DACC Conversion Data Register.
40//! Data which cannot be converted immediately are stored in the DACC FIFO.
41//!
42//! When the FIFO is full or the DACC is not ready to accept conversion requests, the `TXRDY` flag
43//! is inactive.
44//!
45//! The `WORD` field of the DACC Mode Register allows the user to switch between half-word and word
46//! transfer for writing into the FIFO.
47//!
48//! In half-word transfer mode, only the 16 LSB of `DACC_CDR` data are taken into account,
49//! `DACC_CDR[15:0]` is stored in the FIFO.
50//!
51//! The `DACC_CDR[11:0]` field is used as data and the `DACC_CDR[15:12]` bits are used for channel
52//! selection if the `TAG` field is set in the `DACC_MR` register.
53//!
54//! In word transfer mode, each time the `DACC_CDR` register is written to, 2 data items are stored
55//! in the FIFO. The first data item sampled for conversion is `DACC_CDR[15:0]` and the second is
56//! `DACC_CDR[31:16]`.
57//!
58//! Fields `DACC_CDR[15:12]` and `DACC_CDR[31:28]` are used for channel selection if the `TAG` field
59//! is set in the `DACC_MR` register.
60//!
61//! **WARNING:** Writing in the `DACC_CDR` register while the `TXRDY` flag is inactive will corrupt
62//! FIFO data.
63//!
64//!
65//! ## Channel Selection
66//! There are two means by which to select the channel to perform data conversion.
67//!     - The default method is to use the `USER_SEL` field of the DACC Mode Register. Data requests
68//!         will merely be converted to the channel selected with the `USER_SEL` field.
69//!     - A more flexible option is to select the channel for the data to be converted into is to
70//!         use the tag mode, setting the `TAG` field of the DACC Mode Register to `1`. In this mode
71//!         the two bits `DACC_CDR[13:12]`, which are otherwise unused, are employed to select the
72//!         output channel in the same way as the `USER_SEL` field. Finally, if the `WORD` field is
73//!         set, the 2 bits `DACC_CDR[13:12]` are used for channel selection for the first datum and
74//!         `DACC_CDR[29:28]` are used for the channel selection of the second.
75//!
76//!
77//! ## Sleep Mode
78//!
79//! The DACC Sleep Mode maximizes power saving by automatically deactivating the DACC when it is not
80//! being used for conversions.
81//!
82//! When a start conversion request occurs, the DACC is automatically activated. As the analog cell
83//! requires a start-up time, the logic waits during this time and starts the conversion on the
84//! selected channel. When all conversion requests are complete, the DACC is deactivated until the
85//! next request for conversion.
86//!
87//! A fast wake-up mode is available in the DACC Mode Register as a compromise between power saving
88//! strategy and responsiveness. Setting the `FASTW` bit to `1` enables the fast wake-up mode. In
89//! fast wake-up mode the DACC is not fully deactivated while no conversion is requested, thereby
90//! providing less power saving but faster wake-up (4 times faster).
91//!
92//!
93//! ## DACC Timings
94//!
95//! The DACC startup time must be defined by the user in the `STARTUP` field of the DACC Mode
96//! Register.
97//!
98//! This startup time differs depending on the use of the fast wake-up mode along with sleep mode,
99//! in this case the user must set the `STARTUP` time according to the fast wake up and not the
100//! standard startup time.
101//!
102//! A max speed mode is available by setting the `MAXS` bit to `1` in the `DACC_MR` register. Using
103//! this mode, the DAC Controller no longer waits to sample the end of cycle signal coming from the
104//! DACC block to stasrt the next conversion and uses an internal counter instead. This mode gains 2
105//! DACC Clock periods between each consecutive conversion.
106//!
107//! **WARNING:** Using this mode, the `EOC` interrupt of the `DACC_IER` register should not be used
108//! as it is 2 DACC Clock periods late.
109//!
110//! After 20μs the analog voltage resulting from the converted data will start decreasing, therefore
111//! it is necessary to refresh the channel on a regular basis to prevent this voltage loss. This is
112//! the purpose of the `REFRESH` field in the DACC Mode Register, where the user will define the
113//! period for the analog channels to be refreshed.
114//!
115//! **WARNING:** A `REFRESH` period set to `0` will disable the refresh function of the DACC channels.
116//!
117//!
118//! ## Write Protection Registers
119//!
120//! In order to provide security to the DACC, a write protection system has been implemented.
121//!
122//! The write protection mode prevents the writing of certain registers. While this mode is enabled
123//! and one of the protected registers is written, an error is generated in the DACC Write Protect
124//! Status Register and the register write request is cancelled. When a write protection error
125//! occurs, the `WPROTERR` flag is set and the address of the corresponding cancelled register write
126//! is available in the `WPROTADDR` field of the DACC Write Protect Status Register.
127//!
128//! Due to the nature of the write protection feature, enabling and disabling the write protection
129//! mode requires the use of a security code. Thus when enabling or disabling the write protection
130//! mode the `WPKEY` field of the DACC Write Protect Mode Register must be filled with the "DAC"
131//! ASCII code (corresponding to `0x444143`), otherwise the register write is cancelled.
132//!
133//! The protected registers are:
134//!     - Mode Register (`MR`)
135//!     - Channel Enable Register (`CHER`)
136//!     - Channel Disable Register (`CHDR`)
137//!     - Analog Current Register (`ACR`)
138
139pub mod cdr_data;
140
141use crate::{
142    pac::{
143        dacc::mr::{Startup, Trgen, TrgselA, UserSel, Word},
144        DACC, PMC,
145    },
146    peripheral_id::PeripheralId,
147    pmc::{disable_peripheral_clk, enable_peripheral_clk},
148    write_protect::{wpmr_wpsr_impl, WriteProtect},
149};
150use cdr_data::CdrData;
151
152pub const DACC_PID: u32 = PeripheralId::DACC as u32;
153
154/// Digital to analog converter controller
155pub struct Dacc {
156    dacc: DACC,
157}
158
159// wp_impl! {
160//     ///   - Mode register (`DACC_MR`)
161//     ///   - Channel enable register (`DACC_CHER`)
162//     ///   - Channel disable register (`DACC_CHDR`)
163//     ///   - Analog current register (`DACC_ACR`)
164//     Dacc => dacc(wproterr, wprotaddr<u8>): b"DAC",
165// }
166
167wpmr_wpsr_impl! {
168    DACC: {
169        key: 0x444143,
170        addr: u8,
171        wpvs: Wproterr,
172        wpvsrc: Wprotaddr,
173    }
174}
175
176/// The DACC has write protection on the following fields:
177///
178///   - Mode register (`DACC_MR`)
179///   - Channel enable register (`DACC_CHER`)
180///   - Channel disable register (`DACC_CHDR`)
181///   - Analog current register (`DACC_ACR`)
182impl WriteProtect for DACC {}
183
184impl Dacc {
185    #[must_use]
186    /// Make a new DACC converter controller. None of the initialisation necessary to make use of
187    /// the DACC is performed.
188    pub fn new(dacc: DACC) -> Self {
189        Self { dacc }
190    }
191
192    /// Enable the clock for the DACC peripheral.
193    pub fn enable_dacc_clock(&self, pmc: &PMC) {
194        unsafe { enable_peripheral_clk(pmc, DACC_PID) };
195    }
196
197    /// Disable the clock for the DACC peripheral.
198    pub fn disable_dacc_clock(&self, pmc: &PMC) {
199        unsafe { disable_peripheral_clk(pmc, DACC_PID) };
200    }
201
202    /// Perform a software reset the DACC peripheral.
203    pub fn reset(&mut self) {
204        unsafe {
205            self.dacc
206                .cr()
207                .write_with_zero(|cr_reg| cr_reg.swrst().set_bit());
208        }
209    }
210
211    /// Attempt to set the conversion trigger.
212    ///
213    /// Briefly, each trigger is as follows:
214    ///
215    ///   - `TrgselA::External`: Conversions triggered by external signal
216    ///   - `TrgselA::Tiootcc0`: **T**imer **I**/**O** **o**utput of the **t**imer **c**ounter
217    ///       **c**hannel **0**
218    ///   - `TrgselA::Tiootcc1`: **T**imer **I**/**O** **o**utput of the **t**imer **c**ounter
219    ///       **c**hannel **1**
220    ///   - `TrgselA::Tiootcc2`: **T**imer **I**/**O** **o**utput of the **t**imer **c**ounter
221    ///       **c**hannel **2**
222    ///   - `TrgselA::Pwm0`: **PWM** event line **0**
223    ///   - `TrgselA::Pwm1`: **PWM** event line **1**
224    ///
225    /// # Errors
226    ///
227    /// Fails if write protection is enabled.
228    pub fn set_trigger(&mut self, trigger: TrgselA) -> DaccResult {
229        if self.dacc.writeprotect_enabled() {
230            Err(DaccError::WriteProtected)
231        } else {
232            unsafe { self.set_trigger_unchecked(trigger) };
233            Ok(())
234        }
235    }
236
237    /// Attempt to set the external trigger without checking the write protection register.
238    ///
239    /// # Safety
240    ///
241    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
242    ///
243    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
244    #[rustfmt::skip]
245    pub unsafe fn set_trigger_unchecked(&mut self, trigger: TrgselA) {
246        self.dacc.mr().write(|mode_reg| {
247            mode_reg
248                .trgen().variant(Trgen::En)
249                .trgsel().variant(trigger)
250        });
251    }
252
253    /// Attempt to disable external triggering.
254    ///
255    /// # Errors
256    ///
257    /// Fails if write protection is enabled.
258    pub fn disable_trigger(&mut self) -> DaccResult {
259        if self.dacc.writeprotect_enabled() {
260            Err(DaccError::WriteProtected)
261        } else {
262            unsafe { self.disable_trigger_unchecked() };
263            Ok(())
264        }
265    }
266
267    /// Attempt to disable external triggering without checking the write protection register.
268    ///
269    /// # Safety
270    ///
271    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
272    ///
273    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
274    pub unsafe fn disable_trigger_unchecked(&mut self) {
275        self.dacc
276            .mr()
277            .write(|mode_reg| mode_reg.trgen().variant(Trgen::Dis));
278    }
279
280    /// Attempt to set the transfer mode.
281    ///
282    /// The behaviour of these is described on page 1358 of the datasheet, found
283    /// [here](https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11057-32-bit-Cortex-M3-Microcontroller-SAM3X-SAM3A_Datasheet.pdf).
284    ///
285    /// # Errors
286    ///
287    /// Fails if write protection is enabled.
288    pub fn set_transfer_mode(&mut self, mode: Word) -> DaccResult {
289        if self.dacc.writeprotect_enabled() {
290            Err(DaccError::WriteProtected)
291        } else {
292            unsafe { self.set_transfer_mode_unchecked(mode) };
293            Ok(())
294        }
295    }
296
297    /// Attempt to set the transfer mode without checking the write protection register.
298    ///
299    /// # Safety
300    ///
301    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
302    ///
303    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
304    pub unsafe fn set_transfer_mode_unchecked(&mut self, mode: Word) {
305        self.dacc
306            .mr()
307            .write(|mode_reg| mode_reg.word().variant(mode));
308    }
309
310    #[must_use]
311    /// Get the current transfer mode.
312    pub fn get_transfer_mode(&self) -> Word {
313        self.dacc.mr().read().word().variant()
314    }
315
316    /// Enable interrupts flags. A brief description of each interrupt is as follows:
317    ///
318    ///   - `txrdy`: Transmit ready
319    ///   - `eoc`: End of conversion
320    ///   - `endtx`: End of transmit buffer
321    ///   - `txbufe`: Transmit buffer empty
322    pub fn enable_interrupts(&mut self, enable: DaccInterrupts) {
323        unsafe {
324            self.dacc.ier().write_with_zero(|int_en_reg| {
325                if enable.txrdy {
326                    int_en_reg.txrdy().set_bit();
327                }
328                if enable.eoc {
329                    int_en_reg.eoc().set_bit();
330                }
331                if enable.endtx {
332                    int_en_reg.endtx().set_bit();
333                }
334                if enable.txbufe {
335                    int_en_reg.txbufe().set_bit();
336                }
337                int_en_reg
338            });
339        }
340    }
341
342    /// Disable interrupt flags.
343    pub fn disable_interrupts(&mut self, disable: DaccInterrupts) {
344        unsafe {
345            self.dacc.idr().write_with_zero(|int_dis_reg| {
346                if disable.txrdy {
347                    int_dis_reg.txrdy().set_bit();
348                }
349                if disable.eoc {
350                    int_dis_reg.eoc().set_bit();
351                }
352                if disable.endtx {
353                    int_dis_reg.endtx().set_bit();
354                }
355                if disable.txbufe {
356                    int_dis_reg.txbufe().set_bit();
357                }
358                int_dis_reg
359            });
360        }
361    }
362
363    #[must_use]
364    /// Get current interrupt mask.
365    pub fn get_interrupts_mask(&self) -> DaccInterrupts {
366        let imr = self.dacc.imr().read();
367        DaccInterrupts {
368            txrdy: imr.txrdy().bit(),
369            eoc: imr.eoc().bit(),
370            endtx: imr.endtx().bit(),
371            txbufe: imr.txbufe().bit(),
372        }
373    }
374
375    #[must_use]
376    /// Get current interrupt status.
377    pub fn get_interrupts_status(&self) -> DaccInterrupts {
378        let isr = self.dacc.isr().read();
379        DaccInterrupts {
380            txrdy: isr.txrdy().bit(),
381            eoc: isr.eoc().bit(),
382            endtx: isr.endtx().bit(),
383            txbufe: isr.txbufe().bit(),
384        }
385    }
386
387    #[must_use]
388    /// Read the `TXRDY` (transmit ready) interrupt flag.
389    ///
390    ///   - `false`: DACC is not ready to accept new conversion requests.
391    ///   - `true`: DACC is ready to accept new conversion requests.
392    pub fn transmit_ready(&self) -> bool {
393        self.dacc.isr().read().txrdy().bit()
394    }
395
396    #[must_use]
397    /// Read the `EOC` (end of conversion) interrupt flag.
398    ///
399    ///   - `false`: No conversion has been performed since the last
400    ///       [`DACC_ISR`](crate::pac::dacc::isr) read.
401    ///   - `true`: At least one conversion has been performed since the last
402    ///       [`DACC_ISR`](crate::pac::dacc::isr) read.
403    pub fn end_of_conversion(&self) -> bool {
404        self.dacc.isr().read().eoc().bit()
405    }
406
407    #[must_use]
408    /// Read the `ENDTX` (end of DMA) interrupt flag.
409    ///
410    ///   - `false`: The transmit counter register has not reached 0 since the last write in
411    ///       [`DACC_TCR`](crate::pac::dacc::tcr) or [`DACC_TNCR`](crate::pac::dacc::tncr).
412    ///   - `true`: The transmit counter register has reached 0 since the last write in
413    ///       [`DACC_TCR`](crate::pac::dacc::tcr) or [`DACC_TNCR`](crate::pac::dacc::tncr).
414    pub fn end_of_transmit_buffer(&self) -> bool {
415        self.dacc.isr().read().endtx().bit()
416    }
417
418    #[must_use]
419    /// Read the `TXBUFE` (transmit buffer empty) interrupt flag.
420    ///
421    ///   - `false`: The transmit counter register has not reached 0 since the last write in
422    ///       [`DACC_TCR`](crate::pac::dacc::tcr) or [`DACC_TNCR`](crate::pac::dacc::tncr).
423    ///   - `true`: The transmit counter register has reached 0 since the last write in
424    ///       [`DACC_TCR`](crate::pac::dacc::tcr) or [`DACC_TNCR`](crate::pac::dacc::tncr).
425    pub fn transmit_buffer_empty(&self) -> bool {
426        self.dacc.isr().read().txbufe().bit()
427    }
428
429    /// Write data to be converted into the convert data register. The write will succeed only if
430    /// the `TXRDY` flag is set.
431    ///
432    /// # Errors
433    ///
434    /// Fails if `TXRDY` flag is not set.
435    pub fn write_conversion_data<D: CdrData>(&mut self, data: D) -> DaccResult {
436        if self.transmit_ready() {
437            unsafe { self.write_conversion_data_unchecked(data) };
438            Ok(())
439        } else {
440            Err(DaccError::NotTransmitReady)
441        }
442    }
443
444    /// Write data to be converted into the convert data register without checking whether the
445    /// `TXRDY` flag is set.
446    ///
447    /// # Safety
448    ///
449    /// If the `TXRDY` flag is not set, writing to the conversion data register may corrupt the
450    /// DACC FIFO.
451    pub unsafe fn write_conversion_data_unchecked<D: CdrData>(&mut self, data: D) {
452        self.dacc.cdr().write(|cdr| cdr.bits(data.bits()));
453    }
454
455    /// Attempt to set startup time.
456    ///
457    /// Actual startup time values can be in table 45-41 (page 1411) of the datasheet, found
458    /// [here](https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11057-32-bit-Cortex-M3-Microcontroller-SAM3X-SAM3A_Datasheet.pdf).
459    ///
460    /// # Errors
461    ///
462    /// Fails if write protection is enabled.
463    pub fn set_startup(&mut self, startup: Startup) -> DaccResult {
464        if self.dacc.writeprotect_enabled() {
465            Err(DaccError::WriteProtected)
466        } else {
467            unsafe { self.set_startup_unchecked(startup) };
468            Ok(())
469        }
470    }
471
472    /// Attempt to set startup time without checking the write protection register.
473    ///
474    /// # Safety
475    ///
476    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
477    ///
478    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
479    pub unsafe fn set_startup_unchecked(&mut self, startup: Startup) {
480        self.dacc
481            .mr()
482            .write(|mode_reg| mode_reg.startup().variant(startup));
483    }
484
485    /// Attempt to set the refresh period length.
486    ///
487    /// The actual refresh period length is calculated as follows:
488    ///
489    /// `Refresh period = (1024 * refresh) / DACC Clock`
490    ///
491    /// # Errors
492    ///
493    /// Fails if write protection is enabled.
494    pub fn set_refresh(&mut self, refresh: u8) -> DaccResult {
495        if self.dacc.writeprotect_enabled() {
496            Err(DaccError::WriteProtected)
497        } else {
498            unsafe { self.set_refresh_unchecked(refresh) };
499            Ok(())
500        }
501    }
502
503    /// Attempt to set the refresh period length without checking the writeprotect register.
504    ///
505    /// # Safety
506    ///
507    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
508    ///
509    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
510    pub unsafe fn set_refresh_unchecked(&mut self, refresh: u8) {
511        self.dacc
512            .mr()
513            .write(|mode_reg| mode_reg.refresh().bits(refresh));
514    }
515
516    /// Attempt to select the output channel to write CDR values to.
517    ///
518    /// # Errors
519    ///
520    /// Fails if write protection is enabled.
521    pub fn select_channel(&mut self, channel: UserSel) -> DaccResult {
522        if self.dacc.writeprotect_enabled() {
523            Err(DaccError::WriteProtected)
524        } else {
525            unsafe { self.select_channel_unchecked(channel) };
526            Ok(())
527        }
528    }
529
530    /// Attempt to select the output channel without checking the write protection register.
531    ///
532    /// # Safety
533    ///
534    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
535    ///
536    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
537    pub unsafe fn select_channel_unchecked(&mut self, channel: UserSel) {
538        self.dacc
539            .mr()
540            .write(|mode_reg| mode_reg.user_sel().variant(channel));
541    }
542
543    /// Attempt to enable use of tag bits in CDR halfwords.
544    ///
545    /// Tag bits are the two bits that follow the 12 bit value in each halfword. Specifically, the
546    /// breakdown of each halfword is:
547    ///
548    ///   - `halfword[11:0]`: 12 bit value used for DAC output
549    ///   - `halfword[13:12]`: tag bits
550    ///   - `halfword[15:14]`: unused
551    ///
552    /// This is the same for the upper halfword in the CDR if the DACC is set to `WORD` mode, just
553    /// the bit ranges are `[27:16]`, `[29:28]`, and `[31:30]` respectively instead. The tag bits
554    /// are effectively a `USER_SEL` value for each halfword in the CDR.
555    ///
556    /// # Errors
557    ///
558    /// Fails if write protection is enabled.
559    pub fn enable_tag_bits(&mut self) -> DaccResult {
560        if self.dacc.writeprotect_enabled() {
561            Err(DaccError::WriteProtected)
562        } else {
563            unsafe { self.enable_tag_bits_unchecked() };
564            Ok(())
565        }
566    }
567
568    /// Attempt to enable tag bits without checking the write protection register.
569    ///
570    /// # Safety
571    ///
572    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
573    ///
574    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
575    pub unsafe fn enable_tag_bits_unchecked(&mut self) {
576        self.dacc.mr().write(|mode_reg| mode_reg.tag().en());
577    }
578
579    /// Attempt to disable use of tag bits in CDR halfwords.
580    ///
581    /// # Errors
582    ///
583    /// Fails if write protection is enabled.
584    pub fn disable_tag_bits(&mut self) -> DaccResult {
585        if self.dacc.writeprotect_enabled() {
586            Err(DaccError::WriteProtected)
587        } else {
588            unsafe { self.disable_tag_bits_unchecked() };
589            Ok(())
590        }
591    }
592
593    /// Attempt to disable tag bits without checking the write protection register.
594    ///
595    /// # Safety
596    ///
597    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
598    ///
599    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
600    pub unsafe fn disable_tag_bits_unchecked(&mut self) {
601        self.dacc.mr().write(|mode_reg| mode_reg.tag().dis());
602    }
603
604    /// Attempt to enable sleep mode.
605    ///
606    /// In sleep mode, the DAC core and reference voltage circuitry are turned off between
607    /// conversions.
608    ///
609    /// # Errors
610    ///
611    /// Fails if write protection is enabled.
612    pub fn enable_sleep_mode(&mut self) -> DaccResult {
613        if self.dacc.writeprotect_enabled() {
614            Err(DaccError::WriteProtected)
615        } else {
616            unsafe { self.enable_sleep_mode_unchecked() };
617            Ok(())
618        }
619    }
620
621    /// Attempt to enable sleep mode without checking the write protection register.
622    ///
623    /// # Safety
624    ///
625    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
626    ///
627    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
628    pub unsafe fn enable_sleep_mode_unchecked(&mut self) {
629        self.dacc.mr().write(|mode_reg| mode_reg.sleep().set_bit());
630    }
631
632    /// Attempt to disable sleep mode.
633    ///
634    /// When not in sleep mode, the DAC core and reference voltage circuitry are kept on between
635    /// conversions.
636    ///
637    /// # Errors
638    ///
639    /// Fails if write protection is enabled.
640    pub fn disable_sleep_mode(&mut self) -> DaccResult {
641        if self.dacc.writeprotect_enabled() {
642            Err(DaccError::WriteProtected)
643        } else {
644            unsafe { self.disable_sleep_mode_unchecked() };
645            Ok(())
646        }
647    }
648
649    /// Attempt to disable sleep mode without checking the write protection register.
650    ///
651    /// # Safety
652    ///
653    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
654    ///
655    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
656    pub unsafe fn disable_sleep_mode_unchecked(&mut self) {
657        self.dacc
658            .mr()
659            .write(|mode_reg| mode_reg.sleep().clear_bit());
660    }
661
662    /// Attempt to enable fast wake-up mode.
663    ///
664    /// In fast-wake-up mode, the reference voltage is kept on between conversions, but the DAC core
665    /// is kept off.
666    ///
667    /// # Errors
668    ///
669    /// Fails if write protection is enabled.
670    pub fn enable_fast_wakeup(&mut self) -> DaccResult {
671        if self.dacc.writeprotect_enabled() {
672            Err(DaccError::WriteProtected)
673        } else {
674            unsafe { self.enable_fast_wakeup_unchecked() };
675            Ok(())
676        }
677    }
678
679    /// Attempt to enable fast wake-up mode without checking the write protection register.
680    ///
681    /// # Safety
682    ///
683    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
684    ///
685    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
686    pub unsafe fn enable_fast_wakeup_unchecked(&mut self) {
687        self.dacc
688            .mr()
689            .write(|mode_reg| mode_reg.fastwkup().set_bit());
690    }
691
692    /// Attempt to disable fast wake-up mode.
693    ///
694    /// When not in fast wake-up mode, the sleep mode is defined only by the selected sleep mode.
695    ///
696    /// # Errors
697    ///
698    /// Fails if write protection is enabled.
699    pub fn disable_fast_wakeup(&mut self) -> DaccResult {
700        if self.dacc.writeprotect_enabled() {
701            Err(DaccError::WriteProtected)
702        } else {
703            unsafe { self.disable_fast_wakeup_unchecked() };
704            Ok(())
705        }
706    }
707
708    /// Attempt to disable fast wake-up mode without checking the write protection register.
709    ///
710    /// # Safety
711    ///
712    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
713    ///
714    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
715    pub unsafe fn disable_fast_wakeup_unchecked(&mut self) {
716        self.dacc
717            .mr()
718            .write(|mode_reg| mode_reg.fastwkup().clear_bit());
719    }
720
721    /// Attempt to enable max speed mode.
722    ///
723    /// In max speed mode, the DACC no longer waits to sample the end of the cycle signal from the
724    /// DACC block to start the next conversion and uses an internal counter instead. This mode
725    /// gains 2 DACC clock periods between each consecutive conversion.
726    ///
727    /// # Warning
728    ///
729    /// In this mode, the EOC interrupt of the `DACC_IER` register should not be used, as it is 2
730    /// DACC clock periods late.
731    ///
732    /// # Errors
733    ///
734    /// Fails if write protection is enabled.
735    pub fn enable_max_speed(&mut self) -> DaccResult {
736        if self.dacc.writeprotect_enabled() {
737            Err(DaccError::WriteProtected)
738        } else {
739            unsafe { self.enable_max_speed_unchecked() };
740            Ok(())
741        }
742    }
743
744    /// Attempt to enable max speed mode without checking the write protection register.
745    ///
746    /// # Safety
747    ///
748    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
749    ///
750    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
751    pub unsafe fn enable_max_speed_unchecked(&mut self) {
752        self.dacc.mr().write(|mode_reg| mode_reg.maxs().set_bit());
753    }
754
755    /// Attempt to disable max speed mode.
756    ///
757    /// # Errors
758    ///
759    /// Fails if write protection is enabled.
760    pub fn disable_max_speed(&mut self) -> DaccResult {
761        if self.dacc.writeprotect_enabled() {
762            Err(DaccError::WriteProtected)
763        } else {
764            unsafe { self.disable_max_speed_unchecked() };
765            Ok(())
766        }
767    }
768
769    /// Attempt to disable max speed mode without checking the write protection register.
770    ///
771    /// # Safety
772    ///
773    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
774    ///
775    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
776    pub unsafe fn disable_max_speed_unchecked(&mut self) {
777        self.dacc.mr().write(|mode_reg| mode_reg.maxs().clear_bit());
778    }
779
780    /// Attempt to enable DAC output channels.
781    ///
782    /// # Errors
783    ///
784    /// Fails if write protection is enabled.
785    pub fn enable_channels(&mut self, channels: DacChannels) -> DaccResult {
786        if self.dacc.writeprotect_enabled() {
787            Err(DaccError::WriteProtected)
788        } else {
789            unsafe { self.enable_channels_unchecked(channels) };
790            Ok(())
791        }
792    }
793
794    /// Attempt to enable DAC output channels without checking the write protection register.
795    ///
796    /// # Safety
797    ///
798    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
799    ///
800    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
801    pub unsafe fn enable_channels_unchecked(&mut self, channels: DacChannels) {
802        self.dacc.cher().write_with_zero(|channel_en_reg| {
803            if channels.channel_0 {
804                channel_en_reg.ch0().set_bit();
805            }
806            if channels.channel_1 {
807                channel_en_reg.ch1().set_bit();
808            }
809            channel_en_reg
810        });
811    }
812
813    /// Attempt to disable DAC output channels.
814    ///
815    /// # Errors
816    ///
817    /// Fails if write protection is enabled.
818    pub fn disable_channels(&mut self, channels: DacChannels) -> DaccResult {
819        if self.dacc.writeprotect_enabled() {
820            Err(DaccError::WriteProtected)
821        } else {
822            unsafe { self.disable_channels_unchecked(channels) };
823            Ok(())
824        }
825    }
826
827    /// Attempt to disable DAC output channels without checking the write protection register.
828    ///
829    /// # Safety
830    ///
831    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
832    ///
833    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
834    pub unsafe fn disable_channels_unchecked(&mut self, channels: DacChannels) {
835        self.dacc.chdr().write_with_zero(|channel_en_reg| {
836            if channels.channel_0 {
837                channel_en_reg.ch0().clear_bit();
838            }
839            if channels.channel_1 {
840                channel_en_reg.ch1().clear_bit();
841            }
842            channel_en_reg
843        });
844    }
845
846    /// Attempt to apply a configuration to the DAC output channels.
847    ///
848    /// # Errors
849    ///
850    /// Fails if write protection is enabled.
851    pub fn configure_channels(&mut self, channels: DacChannels) -> DaccResult {
852        if self.dacc.writeprotect_enabled() {
853            Err(DaccError::WriteProtected)
854        } else {
855            unsafe { self.configure_channels_unchecked(channels) };
856            Ok(())
857        }
858    }
859
860    /// Attempt to apply a configuration to the DAC output channels without checking the write
861    /// protection register.
862    ///
863    /// # Safety
864    ///
865    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
866    ///
867    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
868    #[rustfmt::skip]
869    pub unsafe fn configure_channels_unchecked(&mut self, channels: DacChannels) {
870        self.dacc.chdr().write_with_zero(|chdr| {
871            chdr
872                .ch0().bit(channels.channel_0)
873                .ch1().bit(channels.channel_1)
874        });
875    }
876
877    #[must_use]
878    /// Get the current status of the DAC channels.
879    pub fn channels_status(&self) -> DacChannels {
880        let chsr = self.dacc.chsr().read();
881        DacChannels {
882            channel_0: chsr.ch0().bit(),
883            channel_1: chsr.ch1().bit(),
884        }
885    }
886
887    /// Attempt to apply the default bias current control config.
888    ///
889    /// # Errors
890    ///
891    /// Fails if write protection is enabled.
892    pub fn apply_default_bias_current_config(&mut self) -> DaccResult {
893        if self.dacc.writeprotect_enabled() {
894            Err(DaccError::WriteProtected)
895        } else {
896            unsafe { self.apply_default_bias_current_config_unchecked() };
897            Ok(())
898        }
899    }
900
901    /// Attempt to apply the default bias current control config without checking the write
902    /// protection register.
903    ///
904    /// # Safety
905    ///
906    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
907    ///
908    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
909    #[rustfmt::skip]
910    pub unsafe fn apply_default_bias_current_config_unchecked(&mut self) {
911        self.dacc.acr().write(|acr| {
912            acr
913                .ibctldaccore().bits(0b01)
914                .ibctlch0().bits(0b10)
915                .ibctlch1().bits(0b10)
916        });
917    }
918}
919
920#[allow(clippy::module_name_repetitions)]
921/// Enum representing the various ways operations with the DACC can fail.
922#[derive(Clone, Copy, Debug)]
923pub enum DaccError {
924    WriteProtected,
925    NotTransmitReady,
926}
927
928#[allow(clippy::module_name_repetitions)]
929pub type DaccResult = Result<(), DaccError>;
930
931#[allow(clippy::struct_excessive_bools, clippy::module_name_repetitions)]
932/// Wrapper struct for DACC interrupts.
933///
934/// A brief description of each interrupt is as follows:
935///
936///   - `txrdy`: Transmit ready
937///   - `eoc`: End of conversion
938///   - `endtx`: End of transmit buffer
939///   - `txbufe`: Transmit buffer empty
940#[derive(Clone, Copy, Debug)]
941pub struct DaccInterrupts {
942    pub txrdy: bool,
943    pub eoc: bool,
944    pub endtx: bool,
945    pub txbufe: bool,
946}
947
948/// Wrapper struct for the status of the DAC output channels.
949#[derive(Clone, Copy, Debug)]
950pub struct DacChannels {
951    pub channel_0: bool,
952    pub channel_1: bool,
953}
954
955#[cfg(feature = "unproven")]
956use crate::CurrentBias;
957
958#[cfg(feature = "unproven")]
959impl Dacc {
960    /// Attempt to set the current bias on the DAC core, which allows you to choose performance or
961    /// power consumption.
962    ///
963    /// # Errors
964    ///
965    /// Fails if write protection is enabled.
966    pub fn set_daccore_current_bias(&mut self, config: CurrentBias) -> DaccResult {
967        if self.dacc.writeprotect_enabled() {
968            Err(DaccError::WriteProtected)
969        } else {
970            unsafe { self.set_daccore_current_bias_unchecked(config) };
971            Ok(())
972        }
973    }
974
975    /// Attempt to set the current bias on the DAC core without checking the write protection
976    /// register.
977    ///
978    /// # Safety
979    ///
980    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
981    ///
982    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
983    pub unsafe fn set_daccore_current_bias_unchecked(&mut self, config: CurrentBias) {
984        self.dacc
985            .acr()
986            .write(|acr| acr.ibctldaccore().bits(config as u8));
987    }
988
989    #[must_use]
990    /// Get the current bias configuration for the DAC core.
991    pub fn get_daccore_current_bias(&self) -> CurrentBias {
992        unsafe { core::mem::transmute(self.dacc.acr().read().ibctldaccore().bits()) }
993    }
994
995    /// Attempt to set the current bias on channel 0, which changes the slew rate of the analog
996    /// output.
997    ///
998    /// # Errors
999    ///
1000    /// Fails if write protection is enabled.
1001    pub fn set_ch0_current_bias(&mut self, config: CurrentBias) -> DaccResult {
1002        if self.dacc.writeprotect_enabled() {
1003            Err(DaccError::WriteProtected)
1004        } else {
1005            unsafe { self.set_ch0_current_bias_unchecked(config) };
1006            Ok(())
1007        }
1008    }
1009
1010    /// Attempt to set the current bias on channel 0 without checking the write protection register.
1011    ///
1012    /// # Safety
1013    ///
1014    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
1015    ///
1016    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
1017    pub unsafe fn set_ch0_current_bias_unchecked(&mut self, config: CurrentBias) {
1018        self.dacc
1019            .acr()
1020            .write(|acr| acr.ibctlch0().bits(config as u8));
1021    }
1022
1023    #[must_use]
1024    /// Get the current bias configuration for channel 0.
1025    pub fn get_ch0_current_bias(&self) -> CurrentBias {
1026        unsafe { core::mem::transmute(self.dacc.acr().read().ibctlch0().bits()) }
1027    }
1028
1029    /// Attempt to set the current bias on channel 1, which changes the slew rate of the analog
1030    /// output.
1031    ///
1032    /// # Errors
1033    ///
1034    /// Fails if write protection is enabled.
1035    pub fn set_ch1_current_bias(&mut self, config: CurrentBias) -> DaccResult {
1036        if self.dacc.writeprotect_enabled() {
1037            Err(DaccError::WriteProtected)
1038        } else {
1039            unsafe { self.set_ch1_current_bias_unchecked(config) };
1040            Ok(())
1041        }
1042    }
1043
1044    /// Attempt to set the current bias on channel 1 without checking the write protection register.
1045    ///
1046    /// # Safety
1047    ///
1048    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
1049    ///
1050    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
1051    pub unsafe fn set_ch1_current_bias_unchecked(&mut self, config: CurrentBias) {
1052        self.dacc
1053            .acr()
1054            .write(|acr| acr.ibctlch1().bits(config as u8));
1055    }
1056
1057    #[must_use]
1058    /// Get the current bias configuration for channel 1.
1059    pub fn get_ch1_current_bias(&self) -> CurrentBias {
1060        unsafe { core::mem::transmute(self.dacc.acr().read().ibctlch1().bits()) }
1061    }
1062
1063    /// Attempt to apply an analog current configuration to the DAC core and both output channels.
1064    /// Fails if write protection is enabled.
1065    ///
1066    /// # Errors
1067    ///
1068    /// Fails if write protection is enabled.
1069    pub fn set_current_config(&mut self, config: DaccCurrentConfig) -> DaccResult {
1070        if self.dacc.writeprotect_enabled() {
1071            Err(DaccError::WriteProtected)
1072        } else {
1073            unsafe { self.set_current_config_unchecked(config) };
1074            Ok(())
1075        }
1076    }
1077
1078    /// Attempt to apply an analog current configuration to the DAC core and both output channels
1079    /// without checking the write protection register.
1080    ///
1081    /// # Safety
1082    ///
1083    /// Operation failure is silent apart from setting the `WPROTERR` flag in the `WPSR` register.
1084    ///
1085    /// May overwrite data in the `WPROTADDR` field of the `WPSR` register if the operation fails.
1086    #[rustfmt::skip]
1087    pub unsafe fn set_current_config_unchecked(&mut self, config: DaccCurrentConfig) {
1088        self.dacc.acr().write(|acr| {
1089            acr
1090                .ibctldaccore().bits(config.daccore as u8)
1091                .ibctlch0().bits(config.ch0 as u8)
1092                .ibctlch1().bits(config.ch1 as u8)
1093        });
1094    }
1095
1096    #[must_use]
1097    /// Get the current bias configuration for the DACC.
1098    pub fn get_current_config(&self) -> DaccCurrentConfig {
1099        DaccCurrentConfig::new(
1100            self.get_daccore_current_bias(),
1101            self.get_ch0_current_bias(),
1102            self.get_ch1_current_bias(),
1103        )
1104    }
1105}
1106
1107#[cfg(feature = "unproven")]
1108#[allow(clippy::module_name_repetitions)]
1109/// Struct containing the current bias configs for the DAC core and both output channels.
1110#[derive(Clone, Copy, Debug)]
1111pub struct DaccCurrentConfig {
1112    pub daccore: CurrentBias,
1113    pub ch0: CurrentBias,
1114    pub ch1: CurrentBias,
1115}
1116
1117#[cfg(feature = "unproven")]
1118impl DaccCurrentConfig {
1119    #[must_use]
1120    pub fn new(daccore: CurrentBias, ch0: CurrentBias, ch1: CurrentBias) -> Self {
1121        Self { daccore, ch0, ch1 }
1122    }
1123}