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}