stm32f4xx/
dac.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5use crate::clocks::{phclk, Stm32f4Clocks};
6use core::cell::Cell;
7use kernel::hil;
8use kernel::platform::chip::ClockInterface;
9use kernel::utilities::registers::interfaces::{ReadWriteable, Writeable};
10use kernel::utilities::registers::{register_bitfields, ReadWrite, WriteOnly};
11use kernel::utilities::StaticRef;
12use kernel::ErrorCode;
13
14/// DAC
15#[repr(C)]
16pub struct DacRegisters {
17    cr: ReadWrite<u32, CR::Register>,
18    swtrigr: WriteOnly<u32, SWTRIGR::Register>,
19    dhr12r1: ReadWrite<u32, DHR12R1::Register>,
20    dhr8r1: ReadWrite<u32, DHR8R1::Register>,
21    dhr12r2: ReadWrite<u32, DHR12R2::Register>,
22    dhr12l2: ReadWrite<u32, DHR12L2::Register>,
23    dhr8r2: ReadWrite<u32, DHR8R2::Register>,
24    dhr12rd: ReadWrite<u32, DHR12RD::Register>,
25    dhr12ld: ReadWrite<u32, DHR12LD::Register>,
26    dhr8rd: ReadWrite<u32, DHR8RD::Register>,
27    dor1: ReadWrite<u32, DOR1::Register>,
28    dor2: ReadWrite<u32, DOR2::Register>,
29}
30
31register_bitfields![u32,
32        /// Control register
33        CR [
34            /// DAC channel 2 DMA underrun interrupt enable
35            DMAUDRIE2 OFFSET(29) NUMBITS(1) [],
36            /// DAC channel 2 DMA enable
37            DMAEN2 OFFSET(28) NUMBITS(1) [],
38            /// DAC channel2 mask/amplitude selector
39            MAMP2 OFFSET(24) NUMBITS(4) [],
40            /// DAC channel2 noise/triangle wave generation enable
41            WAVE2 OFFSET(22) NUMBITS(2) [],
42            /// DAC channel2 trigger selection
43            TSEL2 OFFSET(19) NUMBITS(3) [],
44            /// DAC channel2 trigger enable
45            TEN2 OFFSET(18) NUMBITS(1) [],
46            /// DAC channel2 output buffer disable
47            BOFF2 OFFSET(17) NUMBITS(1) [],
48            /// DAC channel2 enable
49            EN2 OFFSET(16) NUMBITS(1) [],
50            /// DAC channel 1 DMA underrun interrupt enable
51            DMAUDRIE1 OFFSET(13) NUMBITS(1) [],
52            /// DAC channel 1 DMA enable
53            DMAEN1 OFFSET(12) NUMBITS(1) [],
54            /// DAC channel1 mask/amplitude selector
55            MAMP1 OFFSET(8) NUMBITS(4) [],
56            /// DAC channel1 noise/triangle wave generation enable
57            WAVE1 OFFSET(6) NUMBITS(2) [],
58            /// DAC channel2 trigger selection
59            TSEL1 OFFSET(3) NUMBITS(3) [],
60            /// DAC channel2 trigger enable
61            TEN1 OFFSET(2) NUMBITS(1) [],
62            /// DAC channel2 output buffer disable
63            BOFF1 OFFSET(1) NUMBITS(1) [],
64            /// DAC channel1 enable
65            EN1 OFFSET(0) NUMBITS(1) [],
66        ],
67        /// Software trigger register
68        SWTRIGR [
69            /// DAC channel2 software trigger
70            SWTRIG2 OFFSET(1) NUMBITS(1) [],
71            /// DAC channel1 software trigger
72            SWTRIG1 OFFSET(0) NUMBITS(1) []
73        ],
74        /// Channel1 12-bit right-aligned data holding register
75        DHR12R1 [
76            /// DAC channel1 12-bit right-aligned data
77            DACC1DHR OFFSET(0) NUMBITS(12) []
78        ],
79        /// Channel1 8-bit right aligned data holding register
80        DHR8R1 [
81            /// DAC Channel1 8-bit right-aligned data
82            DACC1DHR OFFSET(0) NUMBITS(8) []
83        ],
84        /// Channel2 12-bit right aligned data holding register
85        DHR12R2 [
86            /// DAC channel2 12-bit right aligned data
87            DACC2DHR OFFSET(0) NUMBITS(12) []
88        ],
89        /// Channel2 12-bit left aligned data holding register
90        DHR12L2 [
91            /// DAC channel2 12-bit left-aligned data
92            DACC2DHR OFFSET(0) NUMBITS(12) []
93        ],
94        /// Channel2 8-bit right-aligned data holding register
95        DHR8R2 [
96            /// DAC channel2 8-bit right-aligned data
97            DACC2DHR OFFSET(0) NUMBITS(8) []
98        ],
99        /// Dual DAC 12-bit right-aligned data holding register
100        DHR12RD [
101            /// DAC channel2 12-bit right-aligned data
102            DACC2DHR OFFSET(16) NUMBITS(12) [],
103            /// DAC channel1 12-bit right-aligned data
104            DACC1DHR OFFSET(0) NUMBITS(12) []
105        ],
106        /// Dual DAC 12-bit left aligned data holding register
107        DHR12LD [
108            /// DAC channel2 12-bit left-aligned data
109            DACC2DHR OFFSET(16) NUMBITS(12) [],
110            /// DAC channel1 12-bit left-aligned data
111            DACC1DHR OFFSET(0) NUMBITS(12) []
112        ],
113        /// Dual DAC 8-bit right aligned data holding register
114        DHR8RD [
115            /// DAC channel2 8-bit right-aligned data
116            DACC2DHR OFFSET(8) NUMBITS(8) [],
117            /// DAC channel1 8-bit right-aligned data
118            DACC1DHR OFFSET(0) NUMBITS(8) []
119        ],
120        /// DAC Channel 1 data output register
121        DOR1 [
122            /// DAC channel1 data output
123            DACC1DOR OFFSET(0) NUMBITS(12) []
124        ],
125        /// DAC Channel 2 data output register
126        DOR2 [
127            /// DAC channel2 data output
128            DACC2DOR OFFSET(0) NUMBITS(12) []
129        ],
130        /// DAC status register
131        SR [
132            /// DAC channel2 DMA underrun flag
133            DMAUDR2 OFFSET(29) NUMBITS(1) [],
134            /// DAC channel1 DMA underrun flag
135            DMAUDR1 OFFSET(13) NUMBITS(1) []
136        ]
137];
138
139const DAC_BASE: StaticRef<DacRegisters> =
140    unsafe { StaticRef::new(0x40007400 as *const DacRegisters) };
141
142pub struct Dac<'a> {
143    registers: StaticRef<DacRegisters>,
144    clock: DacClock<'a>,
145    initialized: Cell<bool>,
146    enabled: Cell<bool>,
147}
148
149impl<'a> Dac<'a> {
150    pub const fn new(clocks: &'a dyn Stm32f4Clocks) -> Self {
151        Self {
152            registers: DAC_BASE,
153            clock: DacClock(phclk::PeripheralClock::new(
154                phclk::PeripheralClockType::APB1(phclk::PCLK1::DAC),
155                clocks,
156            )),
157            initialized: Cell::new(false),
158            enabled: Cell::new(false),
159        }
160    }
161
162    fn initialize(&self) -> Result<(), ErrorCode> {
163        if !self.is_enabled_clock() {
164            self.enable_clock();
165        }
166
167        // Clear BOFF1, TEN1, TSEL1, WAVE1 and MAMP1 bits
168        self.registers.cr.modify(CR::BOFF1::CLEAR);
169        self.registers.cr.modify(CR::TEN1::CLEAR);
170        self.registers.cr.modify(CR::TSEL1::CLEAR);
171        self.registers.cr.modify(CR::WAVE1::CLEAR);
172        self.registers.cr.modify(CR::MAMP1::CLEAR);
173
174        self.enable();
175
176        Ok(())
177    }
178
179    fn enable(&self) {
180        self.registers.cr.modify(CR::EN1::SET);
181    }
182
183    // Not currently using interrupt.
184    pub fn handle_interrupt(&self) {}
185
186    fn is_enabled_clock(&self) -> bool {
187        self.clock.is_enabled()
188    }
189
190    fn enable_clock(&self) {
191        self.clock.enable();
192    }
193}
194
195struct DacClock<'a>(phclk::PeripheralClock<'a>);
196
197impl ClockInterface for DacClock<'_> {
198    fn is_enabled(&self) -> bool {
199        self.0.is_enabled()
200    }
201
202    fn enable(&self) {
203        self.0.enable();
204    }
205
206    fn disable(&self) {
207        self.0.disable();
208    }
209}
210
211impl hil::dac::DacChannel for Dac<'_> {
212    fn set_value(&self, value: usize) -> Result<(), ErrorCode> {
213        if !self.initialized.get() {
214            self.initialize()?;
215        }
216
217        if !self.enabled.get() {
218            self.enable();
219        }
220
221        self.registers
222            .dhr12r1
223            .write(DHR12R1::DACC1DHR.val(value as u32));
224        Ok(())
225    }
226}