1 /***************************************************************************//**
2 * @file
3 * @brief Digital to Analog Coversion (DAC) Peripheral API
4 * @author Energy Micro AS
5 * @version 3.0.0
6 *******************************************************************************
7 * @section License
8 * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
9 *******************************************************************************
10 *
11 * Permission is granted to anyone to use this software for any purpose,
12 * including commercial applications, and to alter it and redistribute it
13 * freely, subject to the following restrictions:
14 *
15 * 1. The origin of this software must not be misrepresented; you must not
16 * claim that you wrote the original software.
17 * 2. Altered source versions must be plainly marked as such, and must not be
18 * misrepresented as being the original software.
19 * 3. This notice may not be removed or altered from any source distribution.
20 *
21 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
22 * obligation to support this Software. Energy Micro AS is providing the
23 * Software "AS IS", with no express or implied warranties of any kind,
24 * including, but not limited to, any implied warranties of merchantability
25 * or fitness for any particular purpose or warranties against infringement
26 * of any proprietary rights of a third party.
27 *
28 * Energy Micro AS will not be liable for any consequential, incidental, or
29 * special damages, or any other relief, or for any claim by any third party,
30 * arising from your use of this Software.
31 *
32 ******************************************************************************/
33 #include "em_dac.h"
34 #include "em_cmu.h"
35 #include "em_assert.h"
36 #include "em_bitband.h"
37
38 /***************************************************************************//**
39 * @addtogroup EM_Library
40 * @{
41 ******************************************************************************/
42
43 /***************************************************************************//**
44 * @addtogroup DAC
45 * @brief Digital to Analog Coversion (DAC) Peripheral API
46 * @{
47 ******************************************************************************/
48
49 /*******************************************************************************
50 ******************************* DEFINES ***********************************
51 ******************************************************************************/
52
53 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
54
55 /** Validation of DAC channel for assert statements. */
56 #define DAC_CH_VALID(ch) ((ch) <= 1)
57
58 /** Max DAC clock */
59 #define DAC_MAX_CLOCK 1000000
60
61 /** @endcond */
62
63 /*******************************************************************************
64 ************************** GLOBAL FUNCTIONS *******************************
65 ******************************************************************************/
66
67 /***************************************************************************//**
68 * @brief
69 * Enable/disable DAC channel.
70 *
71 * @param[in] dac
72 * Pointer to DAC peripheral register block.
73 *
74 * @param[in] ch
75 * Channel to enable/disable.
76 *
77 * @param[in] enable
78 * true to enable DAC channel, false to disable.
79 ******************************************************************************/
DAC_Enable(DAC_TypeDef * dac,unsigned int ch,bool enable)80 void DAC_Enable(DAC_TypeDef *dac, unsigned int ch, bool enable)
81 {
82 volatile uint32_t *reg;
83
84 EFM_ASSERT(DAC_REF_VALID(dac));
85 EFM_ASSERT(DAC_CH_VALID(ch));
86
87 if (!ch)
88 {
89 reg = &(dac->CH0CTRL);
90 }
91 else
92 {
93 reg = &(dac->CH1CTRL);
94 }
95
96 BITBAND_Peripheral(reg, _DAC_CH0CTRL_EN_SHIFT, (unsigned int)enable);
97 }
98
99
100 /***************************************************************************//**
101 * @brief
102 * Initialize DAC.
103 *
104 * @details
105 * Initializes common parts for both channels. In addition, channel control
106 * configuration must be done, please refer to DAC_InitChannel().
107 *
108 * @note
109 * This function will disable both channels prior to configuration.
110 *
111 * @param[in] dac
112 * Pointer to DAC peripheral register block.
113 *
114 * @param[in] init
115 * Pointer to DAC initialization structure.
116 ******************************************************************************/
DAC_Init(DAC_TypeDef * dac,const DAC_Init_TypeDef * init)117 void DAC_Init(DAC_TypeDef *dac, const DAC_Init_TypeDef *init)
118 {
119 uint32_t tmp;
120
121 EFM_ASSERT(DAC_REF_VALID(dac));
122
123 /* Make sure both channels are disabled. */
124 BITBAND_Peripheral(&(dac->CH0CTRL), _DAC_CH0CTRL_EN_SHIFT, 0);
125 BITBAND_Peripheral(&(dac->CH1CTRL), _DAC_CH0CTRL_EN_SHIFT, 0);
126
127 /* Load proper calibration data depending on selected reference */
128 switch (init->reference)
129 {
130 case dacRef2V5:
131 dac->CAL = DEVINFO->DAC0CAL1;
132 break;
133
134 case dacRefVDD:
135 dac->CAL = DEVINFO->DAC0CAL2;
136 break;
137
138 default: /* 1.25V */
139 dac->CAL = DEVINFO->DAC0CAL0;
140 break;
141 }
142
143 tmp = ((uint32_t)(init->refresh) << _DAC_CTRL_REFRSEL_SHIFT) |
144 (((uint32_t)(init->prescale) << _DAC_CTRL_PRESC_SHIFT) & _DAC_CTRL_PRESC_MASK) |
145 ((uint32_t)(init->reference) << _DAC_CTRL_REFSEL_SHIFT) |
146 ((uint32_t)(init->outMode) << _DAC_CTRL_OUTMODE_SHIFT) |
147 ((uint32_t)(init->convMode) << _DAC_CTRL_CONVMODE_SHIFT);
148
149 if (init->ch0ResetPre)
150 {
151 tmp |= DAC_CTRL_CH0PRESCRST;
152 }
153
154 if (init->outEnablePRS)
155 {
156 tmp |= DAC_CTRL_OUTENPRS;
157 }
158
159 if (init->sineEnable)
160 {
161 tmp |= DAC_CTRL_SINEMODE;
162 }
163
164 if (init->diff)
165 {
166 tmp |= DAC_CTRL_DIFF;
167 }
168
169 dac->CTRL = tmp;
170 }
171
172
173 /***************************************************************************//**
174 * @brief
175 * Initialize DAC channel.
176 *
177 * @param[in] dac
178 * Pointer to DAC peripheral register block.
179 *
180 * @param[in] init
181 * Pointer to DAC initialization structure.
182 *
183 * @param[in] ch
184 * Channel number to initialize.
185 ******************************************************************************/
DAC_InitChannel(DAC_TypeDef * dac,const DAC_InitChannel_TypeDef * init,unsigned int ch)186 void DAC_InitChannel(DAC_TypeDef *dac,
187 const DAC_InitChannel_TypeDef *init,
188 unsigned int ch)
189 {
190 uint32_t tmp;
191
192 EFM_ASSERT(DAC_REF_VALID(dac));
193 EFM_ASSERT(DAC_CH_VALID(ch));
194
195 tmp = (uint32_t)(init->prsSel) << _DAC_CH0CTRL_PRSSEL_SHIFT;
196
197 if (init->enable)
198 {
199 tmp |= DAC_CH0CTRL_EN;
200 }
201
202 if (init->prsEnable)
203 {
204 tmp |= DAC_CH0CTRL_PRSEN;
205 }
206
207 if (init->refreshEnable)
208 {
209 tmp |= DAC_CH0CTRL_REFREN;
210 }
211
212 if (ch)
213 {
214 dac->CH1CTRL = tmp;
215 }
216 else
217 {
218 dac->CH0CTRL = tmp;
219 }
220 }
221
222
223 /***************************************************************************//**
224 * @brief
225 * Calculate prescaler value used to determine DAC clock.
226 *
227 * @details
228 * The DAC clock is given by: HFPERCLK / (prescale ^ 2).
229 *
230 * @param[in] dacFreq DAC frequency wanted. The frequency will automatically
231 * be adjusted to be below max allowed DAC clock.
232 *
233 * @param[in] hfperFreq Frequency in Hz of reference HFPER clock. Set to 0 to
234 * use currently defined HFPER clock setting.
235 *
236 * @return
237 * Prescaler value to use for DAC in order to achieve a clock value
238 * <= @p dacFreq.
239 ******************************************************************************/
DAC_PrescaleCalc(uint32_t dacFreq,uint32_t hfperFreq)240 uint8_t DAC_PrescaleCalc(uint32_t dacFreq, uint32_t hfperFreq)
241 {
242 uint32_t ret;
243
244 /* Make sure selected DAC clock is below max value */
245 if (dacFreq > DAC_MAX_CLOCK)
246 {
247 dacFreq = DAC_MAX_CLOCK;
248 }
249
250 /* Use current HFPER frequency? */
251 if (!hfperFreq)
252 {
253 hfperFreq = CMU_ClockFreqGet(cmuClock_HFPER);
254 }
255
256 /* Iterate in order to determine best prescale value. Only a few possible */
257 /* values. We start with lowest prescaler value in order to get first */
258 /* equal or below wanted DAC frequency value. */
259 for (ret = 0; ret <= (_DAC_CTRL_PRESC_MASK >> _DAC_CTRL_PRESC_SHIFT); ret++)
260 {
261 if ((hfperFreq >> ret) <= dacFreq)
262 break;
263 }
264
265 return((uint8_t)ret);
266 }
267
268
269 /***************************************************************************//**
270 * @brief
271 * Reset DAC to same state as after a HW reset.
272 *
273 * @param[in] dac
274 * Pointer to ADC peripheral register block.
275 ******************************************************************************/
DAC_Reset(DAC_TypeDef * dac)276 void DAC_Reset(DAC_TypeDef *dac)
277 {
278 /* Disable channels, before resetting other registers. */
279 dac->CH0CTRL = _DAC_CH0CTRL_RESETVALUE;
280 dac->CH1CTRL = _DAC_CH1CTRL_RESETVALUE;
281 dac->CTRL = _DAC_CTRL_RESETVALUE;
282 dac->IEN = _DAC_IEN_RESETVALUE;
283 dac->IFC = _DAC_IFC_MASK;
284 dac->CAL = DEVINFO->DAC0CAL0;
285 dac->BIASPROG = _DAC_BIASPROG_RESETVALUE;
286 /* Do not reset route register, setting should be done independently */
287 }
288
289
290 /** @} (end addtogroup DAC) */
291 /** @} (end addtogroup EM_Library) */
292