EFM32 Gecko Software Documentation  efm32g-doc-5.1.2
em_vdac.c
Go to the documentation of this file.
1 /***************************************************************************/
33 #include "em_vdac.h"
34 #if defined(VDAC_COUNT) && (VDAC_COUNT > 0)
35 #include "em_cmu.h"
36 
37 /***************************************************************************/
42 /***************************************************************************/
47 /*******************************************************************************
48  ******************************* DEFINES ***********************************
49  ******************************************************************************/
50 
54 #define VDAC_CH_VALID(ch) ((ch) <= 1)
55 
57 #define VDAC_MAX_CLOCK 1000000
58 
60 #define VDAC_INTERNAL_CLOCK_FREQ 12000000
61 
64 /*******************************************************************************
65  ************************** GLOBAL FUNCTIONS *******************************
66  ******************************************************************************/
67 
68 /***************************************************************************/
81 void VDAC_Enable(VDAC_TypeDef *vdac, unsigned int ch, bool enable)
82 {
83  EFM_ASSERT(VDAC_REF_VALID(vdac));
84  EFM_ASSERT(VDAC_CH_VALID(ch));
85 
86  if (ch == 0)
87  {
88  if (enable)
89  {
90  vdac->CMD = VDAC_CMD_CH0EN;
91  }
92  else
93  {
94  vdac->CMD = VDAC_CMD_CH0DIS;
95  while (vdac->STATUS & VDAC_STATUS_CH0ENS);
96  }
97  }
98  else
99  {
100  if (enable)
101  {
102  vdac->CMD = VDAC_CMD_CH1EN;
103  }
104  else
105  {
106  vdac->CMD = VDAC_CMD_CH1DIS;
107  while (vdac->STATUS & VDAC_STATUS_CH1ENS);
108  }
109  }
110 }
111 
112 /***************************************************************************/
132 void VDAC_Init(VDAC_TypeDef *vdac, const VDAC_Init_TypeDef *init)
133 {
134  uint32_t cal, tmp = 0;
135  uint32_t const volatile *calData;
136 
137  EFM_ASSERT(VDAC_REF_VALID(vdac));
138 
139  /* Make sure both channels are disabled. */
140  vdac->CMD = VDAC_CMD_CH0DIS | VDAC_CMD_CH1DIS;
141  while (vdac->STATUS & (VDAC_STATUS_CH0ENS | VDAC_STATUS_CH1ENS));
142 
143  /* Get OFFSETTRIM calibration value. */
144  cal = ((DEVINFO->VDAC0CH1CAL & _DEVINFO_VDAC0CH1CAL_OFFSETTRIM_MASK)
145  >> _DEVINFO_VDAC0CH1CAL_OFFSETTRIM_SHIFT)
146  << _VDAC_CAL_OFFSETTRIM_SHIFT;
147 
148  if (init->mainCalibration)
149  {
150  calData = &DEVINFO->VDAC0MAINCAL;
151  }
152  else
153  {
154  calData = &DEVINFO->VDAC0ALTCAL;
155  }
156 
157  /* Get correct GAINERRTRIM calibration value. */
158  switch (init->reference)
159  {
160  case vdacRef1V25Ln:
161  tmp = (*calData & _DEVINFO_VDAC0MAINCAL_GAINERRTRIM1V25LN_MASK)
162  >> _DEVINFO_VDAC0MAINCAL_GAINERRTRIM1V25LN_SHIFT;
163  break;
164 
165  case vdacRef2V5Ln:
166  tmp = (*calData & _DEVINFO_VDAC0MAINCAL_GAINERRTRIM2V5LN_MASK)
167  >> _DEVINFO_VDAC0MAINCAL_GAINERRTRIM2V5LN_SHIFT;
168  break;
169 
170  case vdacRef1V25:
171  tmp = (*calData & _DEVINFO_VDAC0MAINCAL_GAINERRTRIM1V25_MASK)
172  >> _DEVINFO_VDAC0MAINCAL_GAINERRTRIM1V25_SHIFT;
173  break;
174 
175  case vdacRef2V5:
176  tmp = (*calData & _DEVINFO_VDAC0MAINCAL_GAINERRTRIM2V5_MASK)
177  >> _DEVINFO_VDAC0MAINCAL_GAINERRTRIM2V5_SHIFT;
178  break;
179 
180  case vdacRefAvdd:
181  case vdacRefExtPin:
182  tmp = (*calData & _DEVINFO_VDAC0MAINCAL_GAINERRTRIMVDDANAEXTPIN_MASK)
183  >> _DEVINFO_VDAC0MAINCAL_GAINERRTRIMVDDANAEXTPIN_SHIFT;
184  break;
185  }
186 
187  /* Set GAINERRTRIM calibration value. */
188  cal |= tmp << _VDAC_CAL_GAINERRTRIM_SHIFT;
189 
190  /* Get GAINERRTRIMCH1 calibration value. */
191  switch (init->reference)
192  {
193  case vdacRef1V25Ln:
194  case vdacRef1V25:
195  case vdacRefAvdd:
196  case vdacRefExtPin:
197  tmp = (DEVINFO->VDAC0CH1CAL && _DEVINFO_VDAC0CH1CAL_GAINERRTRIMCH1A_MASK)
198  >> _DEVINFO_VDAC0CH1CAL_GAINERRTRIMCH1A_SHIFT;
199  break;
200 
201  case vdacRef2V5Ln:
202  case vdacRef2V5:
203  tmp = (DEVINFO->VDAC0CH1CAL && _DEVINFO_VDAC0CH1CAL_GAINERRTRIMCH1B_MASK)
204  >> _DEVINFO_VDAC0CH1CAL_GAINERRTRIMCH1B_SHIFT;
205  break;
206  }
207 
208  /* Set GAINERRTRIM calibration value. */
209  cal |= tmp << _VDAC_CAL_GAINERRTRIMCH1_SHIFT;
210 
211  tmp = ((uint32_t)init->asyncClockMode << _VDAC_CTRL_DACCLKMODE_SHIFT)
212  | ((uint32_t)init->warmupKeepOn << _VDAC_CTRL_WARMUPMODE_SHIFT)
213  | ((uint32_t)init->refresh << _VDAC_CTRL_REFRESHPERIOD_SHIFT)
214  | (((uint32_t)init->prescaler << _VDAC_CTRL_PRESC_SHIFT)
215  & _VDAC_CTRL_PRESC_MASK)
216  | ((uint32_t)init->reference << _VDAC_CTRL_REFSEL_SHIFT)
217  | ((uint32_t)init->ch0ResetPre << _VDAC_CTRL_CH0PRESCRST_SHIFT)
218  | ((uint32_t)init->outEnablePRS << _VDAC_CTRL_OUTENPRS_SHIFT)
219  | ((uint32_t)init->sineEnable << _VDAC_CTRL_SINEMODE_SHIFT)
220  | ((uint32_t)init->diff << _VDAC_CTRL_DIFF_SHIFT);
221 
222  /* Write to VDAC registers. */
223  vdac->CAL = cal;
224  vdac->CTRL = tmp;
225 }
226 
227 /***************************************************************************/
240 void VDAC_InitChannel(VDAC_TypeDef *vdac,
241  const VDAC_InitChannel_TypeDef *init,
242  unsigned int ch)
243 {
244  uint32_t vdacChCtrl, vdacStatus;
245 
246  EFM_ASSERT(VDAC_REF_VALID(vdac));
247  EFM_ASSERT(VDAC_CH_VALID(ch));
248 
249  /* Make sure both channels are disabled. */
250  vdacStatus = vdac->STATUS;
251  vdac->CMD = VDAC_CMD_CH0DIS | VDAC_CMD_CH1DIS;
252  while (vdac->STATUS & (VDAC_STATUS_CH0ENS | VDAC_STATUS_CH1ENS));
253 
254  vdacChCtrl = ((uint32_t)init->prsSel << _VDAC_CH0CTRL_PRSSEL_SHIFT)
255  | ((uint32_t)init->prsAsync << _VDAC_CH0CTRL_PRSASYNC_SHIFT)
256  | ((uint32_t)init->trigMode << _VDAC_CH0CTRL_TRIGMODE_SHIFT)
257  | ((uint32_t)init->sampleOffMode << _VDAC_CH0CTRL_CONVMODE_SHIFT);
258 
259  if (ch == 0)
260  {
261  vdac->CH0CTRL = vdacChCtrl;
262  }
263  else
264  {
265  vdac->CH1CTRL = vdacChCtrl;
266  }
267 
268  /* Check if the channel must be enabled. */
269  if (init->enable)
270  {
271  if (ch == 0)
272  {
273  vdac->CMD = VDAC_CMD_CH0EN;
274  }
275  else
276  {
277  vdac->CMD = VDAC_CMD_CH1EN;
278  }
279  }
280 
281  /* Check if the other channel had to be turned off above
282  * and needs to be turned on again. */
283  if (ch == 0)
284  {
285  if (vdacStatus & VDAC_STATUS_CH1ENS)
286  {
287  vdac->CMD = VDAC_CMD_CH1EN;
288  }
289  }
290  else
291  {
292  if (vdacStatus & VDAC_STATUS_CH0ENS)
293  {
294  vdac->CMD = VDAC_CMD_CH0EN;
295  }
296  }
297 }
298 
299 /***************************************************************************/
316 void VDAC_ChannelOutputSet(VDAC_TypeDef *vdac,
317  unsigned int channel,
318  uint32_t value)
319 {
320  switch(channel)
321  {
322  case 0:
323  VDAC_Channel0OutputSet(vdac, value);
324  break;
325  case 1:
326  VDAC_Channel1OutputSet(vdac, value);
327  break;
328  default:
329  EFM_ASSERT(0);
330  break;
331  }
332 }
333 
334 /***************************************************************************/
366 uint32_t VDAC_PrescaleCalc(uint32_t vdacFreq, bool syncMode, uint32_t hfperFreq)
367 {
368  uint32_t ret, refFreq;
369 
370  /* Make sure selected VDAC clock is below max value */
371  if (vdacFreq > VDAC_MAX_CLOCK)
372  {
373  vdacFreq = VDAC_MAX_CLOCK;
374  }
375 
376  if (!syncMode)
377  {
378  refFreq = VDAC_INTERNAL_CLOCK_FREQ;
379  }
380  else
381  {
382  if (hfperFreq)
383  {
384  refFreq = hfperFreq;
385  }
386  else
387  {
388  refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
389  }
390  }
391 
392  /* Iterate in order to determine best prescale value. Start with lowest */
393  /* prescaler value in order to get the first equal or less VDAC */
394  /* frequency value. */
395  for (ret = 0; ret <= _VDAC_CTRL_PRESC_MASK >> _VDAC_CTRL_PRESC_SHIFT; ret++)
396  {
397  if ((refFreq / (ret + 1)) <= vdacFreq)
398  {
399  break;
400  }
401  }
402 
403  /* If ret is higher than the max prescaler value, make sure to return
404  the max value. */
405  if (ret > (_VDAC_CTRL_PRESC_MASK >> _VDAC_CTRL_PRESC_SHIFT))
406  {
407  ret = _VDAC_CTRL_PRESC_MASK >> _VDAC_CTRL_PRESC_SHIFT;
408  }
409 
410  return ret;
411 }
412 
413 /***************************************************************************/
420 void VDAC_Reset(VDAC_TypeDef *vdac)
421 {
422  /* Disable channels, before resetting other registers. */
423  vdac->CMD = VDAC_CMD_CH0DIS | VDAC_CMD_CH1DIS;
424  while (vdac->STATUS & (VDAC_STATUS_CH0ENS | VDAC_STATUS_CH1ENS));
425  vdac->CH0CTRL = _VDAC_CH0CTRL_RESETVALUE;
426  vdac->CH1CTRL = _VDAC_CH1CTRL_RESETVALUE;
427  vdac->CH0DATA = _VDAC_CH0DATA_RESETVALUE;
428  vdac->CH1DATA = _VDAC_CH1DATA_RESETVALUE;
429  vdac->CTRL = _VDAC_CTRL_RESETVALUE;
430  vdac->IEN = _VDAC_IEN_RESETVALUE;
431  vdac->IFC = _VDAC_IFC_MASK;
432  vdac->CAL = _VDAC_CAL_RESETVALUE;
433 }
434 
437 #endif /* defined(VDAC_COUNT) && (VDAC_COUNT > 0) */
Clock management unit (CMU) API.
#define DEVINFO
Digital to Analog Converter (VDAC) peripheral API.
uint32_t CMU_ClockFreqGet(CMU_Clock_TypeDef clock)
Get clock frequency for a clock point.
Definition: em_cmu.c:1550