EFM32 Gecko Software Documentation  efm32g-doc-5.1.2
em_idac.c
Go to the documentation of this file.
1 /***************************************************************************/
33 #include "em_idac.h"
34 #if defined(IDAC_COUNT) && (IDAC_COUNT > 0)
35 #include "em_cmu.h"
36 #include "em_assert.h"
37 #include "em_bus.h"
38 
39 /***************************************************************************/
44 /***************************************************************************/
50 /* Fix for errata IDAC_E101 - IDAC output current degradation */
51 #if defined(_SILICON_LABS_32B_SERIES_0) \
52  && (defined(_EFM32_ZERO_FAMILY) || defined(_EFM32_HAPPY_FAMILY))
53 #define ERRATA_FIX_IDAC_E101_EN
54 #endif
55 
57 /*******************************************************************************
58  ************************** GLOBAL FUNCTIONS *******************************
59  ******************************************************************************/
60 
61 
62 /***************************************************************************/
79 void IDAC_Init(IDAC_TypeDef *idac, const IDAC_Init_TypeDef *init)
80 {
81  uint32_t tmp;
82 
83  EFM_ASSERT(IDAC_REF_VALID(idac));
84 
85  tmp = (uint32_t)(init->prsSel);
86 
87  tmp |= init->outMode;
88 
89  if (init->enable)
90  {
91  tmp |= IDAC_CTRL_EN;
92  }
93  if (init->prsEnable)
94  {
95 #if defined(_IDAC_CTRL_OUTENPRS_MASK)
96  tmp |= IDAC_CTRL_OUTENPRS;
97 #else
98  tmp |= IDAC_CTRL_APORTOUTENPRS;
99 #endif
100  }
101  if (init->sinkEnable)
102  {
103  tmp |= IDAC_CTRL_CURSINK;
104  }
105 
106  idac->CTRL = tmp;
107 }
108 
109 
110 /***************************************************************************/
120 void IDAC_Enable(IDAC_TypeDef *idac, bool enable)
121 {
122  EFM_ASSERT(IDAC_REF_VALID(idac));
123  BUS_RegBitWrite(&idac->CTRL, _IDAC_CTRL_EN_SHIFT, enable);
124 }
125 
126 
127 /***************************************************************************/
134 void IDAC_Reset(IDAC_TypeDef *idac)
135 {
136  EFM_ASSERT(IDAC_REF_VALID(idac));
137 
138 #if defined(ERRATA_FIX_IDAC_E101_EN)
139  /* Fix for errata IDAC_E101 - IDAC output current degradation:
140  Instead of disabling it we will put it in it's lowest power state (50 nA)
141  to avoid degradation over time */
142 
143  /* Make sure IDAC is enabled with disabled output */
144  idac->CTRL = _IDAC_CTRL_RESETVALUE | IDAC_CTRL_EN;
145 
146  /* Set lowest current (50 nA) */
147  idac->CURPROG = IDAC_CURPROG_RANGESEL_RANGE0 |
148  (0x0 << _IDAC_CURPROG_STEPSEL_SHIFT);
149 
150  /* Enable duty-cycling for all energy modes */
151  idac->DUTYCONFIG = IDAC_DUTYCONFIG_DUTYCYCLEEN;
152 #else
153  idac->CTRL = _IDAC_CTRL_RESETVALUE;
154  idac->CURPROG = _IDAC_CURPROG_RESETVALUE;
155  idac->DUTYCONFIG = _IDAC_DUTYCONFIG_RESETVALUE;
156 #endif
157 #if defined ( _IDAC_CAL_MASK )
158  idac->CAL = _IDAC_CAL_RESETVALUE;
159 #endif
160 }
161 
162 
163 /***************************************************************************/
173 void IDAC_MinimalOutputTransitionMode(IDAC_TypeDef *idac, bool enable)
174 {
175  EFM_ASSERT(IDAC_REF_VALID(idac));
176  BUS_RegBitWrite(&idac->CTRL, _IDAC_CTRL_MINOUTTRANS_SHIFT, enable);
177 }
178 
179 
180 /***************************************************************************/
196 void IDAC_RangeSet(IDAC_TypeDef *idac, const IDAC_Range_TypeDef range)
197 {
198  uint32_t tmp;
199 #if defined( _IDAC_CURPROG_TUNING_MASK )
200  uint32_t diCal0;
201  uint32_t diCal1;
202 #endif
203 
204  EFM_ASSERT(IDAC_REF_VALID(idac));
205  EFM_ASSERT(((uint32_t)range >> _IDAC_CURPROG_RANGESEL_SHIFT)
206  <= (_IDAC_CURPROG_RANGESEL_MASK >> _IDAC_CURPROG_RANGESEL_SHIFT));
207 
208 #if defined ( _IDAC_CAL_MASK )
209 
210  /* Load proper calibration data depending on selected range */
211  switch ((IDAC_Range_TypeDef)range)
212  {
213  case idacCurrentRange0:
214  idac->CAL = (DEVINFO->IDAC0CAL0 & _DEVINFO_IDAC0CAL0_RANGE0_MASK)
215  >> _DEVINFO_IDAC0CAL0_RANGE0_SHIFT;
216  break;
217  case idacCurrentRange1:
218  idac->CAL = (DEVINFO->IDAC0CAL0 & _DEVINFO_IDAC0CAL0_RANGE1_MASK)
219  >> _DEVINFO_IDAC0CAL0_RANGE1_SHIFT;
220  break;
221  case idacCurrentRange2:
222  idac->CAL = (DEVINFO->IDAC0CAL0 & _DEVINFO_IDAC0CAL0_RANGE2_MASK)
223  >> _DEVINFO_IDAC0CAL0_RANGE2_SHIFT;
224  break;
225  case idacCurrentRange3:
226  idac->CAL = (DEVINFO->IDAC0CAL0 & _DEVINFO_IDAC0CAL0_RANGE3_MASK)
227  >> _DEVINFO_IDAC0CAL0_RANGE3_SHIFT;
228  break;
229  }
230 
231  tmp = idac->CURPROG & ~_IDAC_CURPROG_RANGESEL_MASK;
232  tmp |= (uint32_t)range;
233 
234 #elif defined( _IDAC_CURPROG_TUNING_MASK )
235 
236  /* Load calibration data depending on selected range and sink/source mode */
237  /* TUNING (calibration) field in CURPROG register. */
238  EFM_ASSERT(idac == IDAC0);
239  diCal0 = DEVINFO->IDAC0CAL0;
240  diCal1 = DEVINFO->IDAC0CAL1;
241 
242  tmp = idac->CURPROG & ~(_IDAC_CURPROG_TUNING_MASK
243  | _IDAC_CURPROG_RANGESEL_MASK);
244  if (idac->CTRL & IDAC_CTRL_CURSINK)
245  {
246  switch (range)
247  {
248  case idacCurrentRange0:
249  tmp |= ((diCal1 & _DEVINFO_IDAC0CAL1_SINKRANGE0TUNING_MASK)
250  >> _DEVINFO_IDAC0CAL1_SINKRANGE0TUNING_SHIFT)
251  << _IDAC_CURPROG_TUNING_SHIFT;
252  break;
253 
254  case idacCurrentRange1:
255  tmp |= ((diCal1 & _DEVINFO_IDAC0CAL1_SINKRANGE1TUNING_MASK)
256  >> _DEVINFO_IDAC0CAL1_SINKRANGE1TUNING_SHIFT)
257  << _IDAC_CURPROG_TUNING_SHIFT;
258  break;
259 
260  case idacCurrentRange2:
261  tmp |= ((diCal1 & _DEVINFO_IDAC0CAL1_SINKRANGE2TUNING_MASK)
262  >> _DEVINFO_IDAC0CAL1_SINKRANGE2TUNING_SHIFT)
263  << _IDAC_CURPROG_TUNING_SHIFT;
264  break;
265 
266  case idacCurrentRange3:
267  tmp |= ((diCal1 & _DEVINFO_IDAC0CAL1_SINKRANGE3TUNING_MASK)
268  >> _DEVINFO_IDAC0CAL1_SINKRANGE3TUNING_SHIFT)
269  << _IDAC_CURPROG_TUNING_SHIFT;
270  break;
271  }
272  }
273  else
274  {
275  switch (range)
276  {
277  case idacCurrentRange0:
278  tmp |= ((diCal0 & _DEVINFO_IDAC0CAL0_SOURCERANGE0TUNING_MASK)
279  >> _DEVINFO_IDAC0CAL0_SOURCERANGE0TUNING_SHIFT)
280  << _IDAC_CURPROG_TUNING_SHIFT;
281  break;
282 
283  case idacCurrentRange1:
284  tmp |= ((diCal0 & _DEVINFO_IDAC0CAL0_SOURCERANGE1TUNING_MASK)
285  >> _DEVINFO_IDAC0CAL0_SOURCERANGE1TUNING_SHIFT)
286  << _IDAC_CURPROG_TUNING_SHIFT;
287  break;
288 
289  case idacCurrentRange2:
290  tmp |= ((diCal0 & _DEVINFO_IDAC0CAL0_SOURCERANGE2TUNING_MASK)
291  >> _DEVINFO_IDAC0CAL0_SOURCERANGE2TUNING_SHIFT)
292  << _IDAC_CURPROG_TUNING_SHIFT;
293  break;
294 
295  case idacCurrentRange3:
296  tmp |= ((diCal0 & _DEVINFO_IDAC0CAL0_SOURCERANGE3TUNING_MASK)
297  >> _DEVINFO_IDAC0CAL0_SOURCERANGE3TUNING_SHIFT)
298  << _IDAC_CURPROG_TUNING_SHIFT;
299  break;
300  }
301  }
302 
303  tmp |= (uint32_t)range;
304 
305 #else
306 #warning "IDAC calibration register definition unknown."
307 #endif
308 
309  idac->CURPROG = tmp;
310 }
311 
312 
313 /***************************************************************************/
323 void IDAC_StepSet(IDAC_TypeDef *idac, const uint32_t step)
324 {
325  uint32_t tmp;
326 
327  EFM_ASSERT(IDAC_REF_VALID(idac));
328  EFM_ASSERT(step <= (_IDAC_CURPROG_STEPSEL_MASK >> _IDAC_CURPROG_STEPSEL_SHIFT));
329 
330  tmp = idac->CURPROG & ~_IDAC_CURPROG_STEPSEL_MASK;
331  tmp |= step << _IDAC_CURPROG_STEPSEL_SHIFT;
332 
333  idac->CURPROG = tmp;
334 }
335 
336 
337 /***************************************************************************/
347 void IDAC_OutEnable(IDAC_TypeDef *idac, bool enable)
348 {
349  EFM_ASSERT(IDAC_REF_VALID(idac));
350 #if defined(_IDAC_CTRL_OUTEN_MASK)
351  BUS_RegBitWrite(&idac->CTRL, _IDAC_CTRL_OUTEN_SHIFT, enable);
352 #else
353  BUS_RegBitWrite(&idac->CTRL, _IDAC_CTRL_APORTOUTEN_SHIFT, enable);
354 #endif
355 }
356 
357 
361 #endif /* defined(IDAC_COUNT) && (IDAC_COUNT > 0) */
Clock management unit (CMU) API.
Emlib peripheral API "assert" implementation.
RAM and peripheral bit-field set and clear API.
Current Digital to Analog Converter (IDAC) peripheral API.
#define DEVINFO
__STATIC_INLINE void BUS_RegBitWrite(volatile uint32_t *addr, unsigned int bit, unsigned int val)
Perform a single-bit write operation on a peripheral register.
Definition: em_bus.h:148