1 /***************************************************************************//**
2  * @file
3  * @brief Analog to Digital Converter (ADC) 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 #ifndef __EM_ADC_H
34 #define __EM_ADC_H
35 
36 #include <stdbool.h>
37 #include "em_part.h"
38 
39 #ifdef __cplusplus
40 extern "C" {
41 #endif
42 
43 /***************************************************************************//**
44  * @addtogroup EM_Library
45  * @{
46  ******************************************************************************/
47 
48 /***************************************************************************//**
49  * @addtogroup ADC
50  * @{
51  ******************************************************************************/
52 
53 /*******************************************************************************
54  ********************************   ENUMS   ************************************
55  ******************************************************************************/
56 
57 /** Acquisition time (in ADC clock cycles). */
58 typedef enum
59 {
60   adcAcqTime1   = _ADC_SINGLECTRL_AT_1CYCLE,    /**< 1 clock cycle. */
61   adcAcqTime2   = _ADC_SINGLECTRL_AT_2CYCLES,   /**< 2 clock cycles. */
62   adcAcqTime4   = _ADC_SINGLECTRL_AT_4CYCLES,   /**< 4 clock cycles. */
63   adcAcqTime8   = _ADC_SINGLECTRL_AT_8CYCLES,   /**< 8 clock cycles. */
64   adcAcqTime16  = _ADC_SINGLECTRL_AT_16CYCLES,  /**< 16 clock cycles. */
65   adcAcqTime32  = _ADC_SINGLECTRL_AT_32CYCLES,  /**< 32 clock cycles. */
66   adcAcqTime64  = _ADC_SINGLECTRL_AT_64CYCLES,  /**< 64 clock cycles. */
67   adcAcqTime128 = _ADC_SINGLECTRL_AT_128CYCLES, /**< 128 clock cycles. */
68   adcAcqTime256 = _ADC_SINGLECTRL_AT_256CYCLES  /**< 256 clock cycles. */
69 } ADC_AcqTime_TypeDef;
70 
71 
72 /** Lowpass filter mode. */
73 typedef enum
74 {
75   /** No filter or decoupling capacitor. */
76   adcLPFilterBypass = _ADC_CTRL_LPFMODE_BYPASS,
77 
78   /** On-chip RC filter. */
79   adcLPFilterRC     = _ADC_CTRL_LPFMODE_RCFILT,
80 
81   /** On-chip decoupling capacitor. */
82   adcLPFilterDeCap  = _ADC_CTRL_LPFMODE_DECAP
83 } ADC_LPFilter_TypeDef;
84 
85 
86 /** Oversample rate select. */
87 typedef enum
88 {
89   /** 2 samples per conversion result. */
90   adcOvsRateSel2    = _ADC_CTRL_OVSRSEL_X2,
91 
92   /** 4 samples per conversion result. */
93   adcOvsRateSel4    = _ADC_CTRL_OVSRSEL_X4,
94 
95   /** 8 samples per conversion result. */
96   adcOvsRateSel8    = _ADC_CTRL_OVSRSEL_X8,
97 
98   /** 16 samples per conversion result. */
99   adcOvsRateSel16   = _ADC_CTRL_OVSRSEL_X16,
100 
101   /** 32 samples per conversion result. */
102   adcOvsRateSel32   = _ADC_CTRL_OVSRSEL_X32,
103 
104   /** 64 samples per conversion result. */
105   adcOvsRateSel64   = _ADC_CTRL_OVSRSEL_X64,
106 
107   /** 128 samples per conversion result. */
108   adcOvsRateSel128  = _ADC_CTRL_OVSRSEL_X128,
109 
110   /** 256 samples per conversion result. */
111   adcOvsRateSel256  = _ADC_CTRL_OVSRSEL_X256,
112 
113   /** 512 samples per conversion result. */
114   adcOvsRateSel512  = _ADC_CTRL_OVSRSEL_X512,
115 
116   /** 1024 samples per conversion result. */
117   adcOvsRateSel1024 = _ADC_CTRL_OVSRSEL_X1024,
118 
119   /** 2048 samples per conversion result. */
120   adcOvsRateSel2048 = _ADC_CTRL_OVSRSEL_X2048,
121 
122   /** 4096 samples per conversion result. */
123   adcOvsRateSel4096 = _ADC_CTRL_OVSRSEL_X4096
124 } ADC_OvsRateSel_TypeDef;
125 
126 
127 /** Peripheral Reflex System signal used to trigger single sample. */
128 typedef enum
129 {
130   adcPRSSELCh0 = _ADC_SINGLECTRL_PRSSEL_PRSCH0, /**< PRS channel 0. */
131   adcPRSSELCh1 = _ADC_SINGLECTRL_PRSSEL_PRSCH1, /**< PRS channel 1. */
132   adcPRSSELCh2 = _ADC_SINGLECTRL_PRSSEL_PRSCH2, /**< PRS channel 2. */
133   adcPRSSELCh3 = _ADC_SINGLECTRL_PRSSEL_PRSCH3, /**< PRS channel 3. */
134   adcPRSSELCh4 = _ADC_SINGLECTRL_PRSSEL_PRSCH4, /**< PRS channel 4. */
135   adcPRSSELCh5 = _ADC_SINGLECTRL_PRSSEL_PRSCH5, /**< PRS channel 5. */
136   adcPRSSELCh6 = _ADC_SINGLECTRL_PRSSEL_PRSCH6, /**< PRS channel 6. */
137   adcPRSSELCh7 = _ADC_SINGLECTRL_PRSSEL_PRSCH7  /**< PRS channel 7. */
138 } ADC_PRSSEL_TypeDef;
139 
140 
141 /** Reference to ADC sample. */
142 typedef enum
143 {
144   /** Internal 1.25V reference. */
145   adcRef1V25      = _ADC_SINGLECTRL_REF_1V25,
146 
147   /** Internal 2.5V reference. */
148   adcRef2V5       = _ADC_SINGLECTRL_REF_2V5,
149 
150   /** Buffered VDD. */
151   adcRefVDD       = _ADC_SINGLECTRL_REF_VDD,
152 
153   /** Internal differential 5V reference. */
154   adcRef5VDIFF    = _ADC_SINGLECTRL_REF_5VDIFF,
155 
156   /** Single ended ext. ref. from pin 6. */
157   adcRefExtSingle = _ADC_SINGLECTRL_REF_EXTSINGLE,
158 
159   /** Differential ext. ref. from pin 6 and 7. */
160   adcRef2xExtDiff = _ADC_SINGLECTRL_REF_2XEXTDIFF,
161 
162   /** Unbuffered 2xVDD. */
163   adcRef2xVDD     = _ADC_SINGLECTRL_REF_2XVDD
164 } ADC_Ref_TypeDef;
165 
166 
167 /** Sample resolution. */
168 typedef enum
169 {
170   adcRes12Bit = _ADC_SINGLECTRL_RES_12BIT, /**< 12 bit sampling. */
171   adcRes8Bit  = _ADC_SINGLECTRL_RES_8BIT,  /**< 8 bit sampling. */
172   adcRes6Bit  = _ADC_SINGLECTRL_RES_6BIT,  /**< 6 bit sampling. */
173   adcResOVS   = _ADC_SINGLECTRL_RES_OVS    /**< Oversampling. */
174 } ADC_Res_TypeDef;
175 
176 
177 /** Single sample input selection. */
178 typedef enum
179 {
180   /* Differential mode disabled */
181   adcSingleInpCh0      = _ADC_SINGLECTRL_INPUTSEL_CH0,      /**< Channel 0. */
182   adcSingleInpCh1      = _ADC_SINGLECTRL_INPUTSEL_CH1,      /**< Channel 1. */
183   adcSingleInpCh2      = _ADC_SINGLECTRL_INPUTSEL_CH2,      /**< Channel 2. */
184   adcSingleInpCh3      = _ADC_SINGLECTRL_INPUTSEL_CH3,      /**< Channel 3. */
185   adcSingleInpCh4      = _ADC_SINGLECTRL_INPUTSEL_CH4,      /**< Channel 4. */
186   adcSingleInpCh5      = _ADC_SINGLECTRL_INPUTSEL_CH5,      /**< Channel 5. */
187   adcSingleInpCh6      = _ADC_SINGLECTRL_INPUTSEL_CH6,      /**< Channel 6. */
188   adcSingleInpCh7      = _ADC_SINGLECTRL_INPUTSEL_CH7,      /**< Channel 7. */
189   adcSingleInpTemp     = _ADC_SINGLECTRL_INPUTSEL_TEMP,     /**< Temperature reference. */
190   adcSingleInpVDDDiv3  = _ADC_SINGLECTRL_INPUTSEL_VDDDIV3,  /**< VDD divided by 3. */
191   adcSingleInpVDD      = _ADC_SINGLECTRL_INPUTSEL_VDD,      /**< VDD. */
192   adcSingleInpVSS      = _ADC_SINGLECTRL_INPUTSEL_VSS,      /**< VSS. */
193   adcSingleInpVrefDiv2 = _ADC_SINGLECTRL_INPUTSEL_VREFDIV2, /**< Vref divided by 2. */
194   adcSingleInpDACOut0  = _ADC_SINGLECTRL_INPUTSEL_DAC0OUT0, /**< DAC output 0. */
195   adcSingleInpDACOut1  = _ADC_SINGLECTRL_INPUTSEL_DAC0OUT1, /**< DAC output 1. */
196   /* TBD: Use define when available */
197   adcSingleInpATEST    = 15,                                /**< ATEST. */
198 
199   /* Differential mode enabled */
200   adcSingleInpCh0Ch1   = _ADC_SINGLECTRL_INPUTSEL_CH0CH1,   /**< Positive Ch0, negative Ch1. */
201   adcSingleInpCh2Ch3   = _ADC_SINGLECTRL_INPUTSEL_CH2CH3,   /**< Positive Ch2, negative Ch3. */
202   adcSingleInpCh4Ch5   = _ADC_SINGLECTRL_INPUTSEL_CH4CH5,   /**< Positive Ch4, negative Ch5. */
203   adcSingleInpCh6Ch7   = _ADC_SINGLECTRL_INPUTSEL_CH6CH7,   /**< Positive Ch6, negative Ch7. */
204   /* TBD: Use define when available */
205   adcSingleInpDiff0    = 4                                  /**< Differential 0. */
206 } ADC_SingleInput_TypeDef;
207 
208 
209 /** Acquisition time (in ADC clock cycles). */
210 typedef enum
211 {
212   /** Start single conversion. */
213   adcStartSingle        = ADC_CMD_SINGLESTART,
214 
215   /** Start scan sequence. */
216   adcStartScan          = ADC_CMD_SCANSTART,
217 
218   /**
219    * Start scan sequence and single conversion, typically used when tailgating
220    * single conversion after scan sequence.
221    */
222   adcStartScanAndSingle = ADC_CMD_SCANSTART | ADC_CMD_SINGLESTART
223 } ADC_Start_TypeDef;
224 
225 
226 /** Warm-up mode. */
227 typedef enum
228 {
229   /** ADC shutdown after each conversion. */
230   adcWarmupNormal          = _ADC_CTRL_WARMUPMODE_NORMAL,
231 
232   /** Do not warm-up bandgap references. */
233   adcWarmupFastBG          = _ADC_CTRL_WARMUPMODE_FASTBG,
234 
235   /** Reference selected for scan mode kept warm.*/
236   adcWarmupKeepScanRefWarm = _ADC_CTRL_WARMUPMODE_KEEPSCANREFWARM,
237 
238   /** ADC and reference selected for scan mode kept warm.*/
239   adcWarmupKeepADCWarm     = _ADC_CTRL_WARMUPMODE_KEEPADCWARM
240 } ADC_Warmup_TypeDef;
241 
242 
243 /*******************************************************************************
244  *******************************   STRUCTS   ***********************************
245  ******************************************************************************/
246 
247 /** ADC init structure, common for single conversion and scan sequence. */
248 typedef struct
249 {
250   /**
251    * Oversampling rate select. In order to have any effect, oversampling must
252    * be enabled for single/scan mode.
253    */
254   ADC_OvsRateSel_TypeDef ovsRateSel;
255 
256   /** Lowpass or decoupling capacitor filter to use. */
257   ADC_LPFilter_TypeDef   lpfMode;
258 
259   /** Warm-up mode to use for ADC. */
260   ADC_Warmup_TypeDef     warmUpMode;
261 
262   /**
263    * Timebase used for ADC warm up. Select N to give (N+1)HFPERCLK cycles.
264    * (Additional delay is added for bandgap references, please refer to the
265    * reference manual.) Normally, N should be selected so that the timebase
266    * is at least 1 us. See ADC_TimebaseCalc() for a way to obtain
267    * a suggested timebase of at least 1 us.
268    */
269   uint8_t                timebase;
270 
271   /** Clock division factor N, ADC clock =  HFPERCLK / (N + 1). */
272   uint8_t                prescale;
273 
274   /** Enable/disable conversion tailgating. */
275   bool                   tailgate;
276 } ADC_Init_TypeDef;
277 
278 /** Default config for ADC init structure. */
279 #define ADC_INIT_DEFAULT                                                     \
280   { adcOvsRateSel2,                /* 2x oversampling (if enabled). */       \
281     adcLPFilterBypass,             /* No input filter selected. */           \
282     adcWarmupNormal,               /* ADC shutdown after each conversion. */ \
283     _ADC_CTRL_TIMEBASE_DEFAULT,    /* Use HW default value. */               \
284     _ADC_CTRL_PRESC_DEFAULT,       /* Use HW default value. */               \
285     false                          /* Do not use tailgate. */                \
286   }
287 
288 
289 /** Scan sequence init structure. */
290 typedef struct
291 {
292   /**
293    * Peripheral reflex system trigger selection. Only applicable if @p prsEnable
294    * is enabled.
295    */
296   ADC_PRSSEL_TypeDef  prsSel;
297 
298   /** Acquisition time (in ADC clock cycles). */
299   ADC_AcqTime_TypeDef acqTime;
300 
301   /**
302    * Sample reference selection. Notice that for external references, the
303    * ADC calibration register must be set explicitly.
304    */
305   ADC_Ref_TypeDef     reference;
306 
307   /** Sample resolution. */
308   ADC_Res_TypeDef     resolution;
309 
310   /**
311    * Input scan selection. If single ended (@p diff is false), use logical
312    * combination of ADC_SCANCTRL_INPUTMASK_CHx defines. If differential input
313    * (@p diff is true), use logical combination of ADC_SCANCTRL_INPUTMASK_CHxCHy
314    * defines. (Notice underscore prefix for defines used.)
315    */
316   uint32_t            input;
317 
318   /** Select if single ended or differential input. */
319   bool                diff;
320 
321   /** Peripheral reflex system trigger enable. */
322   bool                prsEnable;
323 
324   /** Select if left adjustment should be done. */
325   bool                leftAdjust;
326 
327   /** Select if continuous conversion until explicit stop. */
328   bool                rep;
329 } ADC_InitScan_TypeDef;
330 
331 /** Default config for ADC scan init structure. */
332 #define ADC_INITSCAN_DEFAULT                                                        \
333   { adcPRSSELCh0,              /* PRS ch0 (if enabled). */                          \
334     adcAcqTime1,               /* 1 ADC_CLK cycle acquisition time. */              \
335     adcRef1V25,                /* 1.25V internal reference. */                      \
336     adcRes12Bit,               /* 12 bit resolution. */                             \
337     0,                         /* No input selected. */                             \
338     false,                     /* Single ended input. */                            \
339     false,                     /* PRS disabled. */                                  \
340     false,                     /* Right adjust. */                                  \
341     false                      /* Deactivate conversion after one scan sequence. */ \
342   }
343 
344 
345 /** Single conversion init structure. */
346 typedef struct
347 {
348   /**
349    * Peripheral reflex system trigger selection. Only applicable if @p prsEnable
350    * is enabled.
351    */
352   ADC_PRSSEL_TypeDef      prsSel;
353 
354   /** Acquisition time (in ADC clock cycles). */
355   ADC_AcqTime_TypeDef     acqTime;
356 
357   /**
358    * Sample reference selection. Notice that for external references, the
359    * ADC calibration register must be set explicitly.
360    */
361   ADC_Ref_TypeDef         reference;
362 
363   /** Sample resolution. */
364   ADC_Res_TypeDef         resolution;
365 
366   /**
367    * Sample input selection, use single ended or differential input according
368    * to setting of @p diff.
369    */
370   ADC_SingleInput_TypeDef input;
371 
372   /** Select if single ended or differential input. */
373   bool                    diff;
374 
375   /** Peripheral reflex system trigger enable. */
376   bool                    prsEnable;
377 
378   /** Select if left adjustment should be done. */
379   bool                    leftAdjust;
380 
381   /** Select if continuous conversion until explicit stop. */
382   bool                    rep;
383 } ADC_InitSingle_TypeDef;
384 
385 /** Default config for ADC single conversion init structure. */
386 #define ADC_INITSINGLE_DEFAULT                                                      \
387   { adcPRSSELCh0,              /* PRS ch0 (if enabled). */                          \
388     adcAcqTime1,               /* 1 ADC_CLK cycle acquisition time. */              \
389     adcRef1V25,                /* 1.25V internal reference. */                      \
390     adcRes12Bit,               /* 12 bit resolution. */                             \
391     adcSingleInpCh0,           /* CH0 input selected. */                            \
392     false,                     /* Single ended input. */                            \
393     false,                     /* PRS disabled. */                                  \
394     false,                     /* Right adjust. */                                  \
395     false                      /* Deactivate conversion after one scan sequence. */ \
396   }
397 
398 
399 /*******************************************************************************
400  *****************************   PROTOTYPES   **********************************
401  ******************************************************************************/
402 
403 /***************************************************************************//**
404  * @brief
405  *   Get single conversion result.
406  *
407  * @note
408  *   Do only use if single conversion data valid.
409  *
410  * @param[in] adc
411  *   Pointer to ADC peripheral register block.
412  *
413  * @return
414  *
415  ******************************************************************************/
ADC_DataSingleGet(ADC_TypeDef * adc)416 __STATIC_INLINE uint32_t ADC_DataSingleGet(ADC_TypeDef *adc)
417 {
418   return(adc->SINGLEDATA);
419 }
420 
421 
422 /***************************************************************************//**
423  * @brief
424  *   Get scan result.
425  *
426  * @note
427  *   Do only use if scan data valid.
428  *
429  * @param[in] adc
430  *   Pointer to ADC peripheral register block.
431  ******************************************************************************/
ADC_DataScanGet(ADC_TypeDef * adc)432 __STATIC_INLINE uint32_t ADC_DataScanGet(ADC_TypeDef *adc)
433 {
434   return(adc->SCANDATA);
435 }
436 
437 
438 void ADC_Init(ADC_TypeDef *adc, const ADC_Init_TypeDef *init);
439 void ADC_InitScan(ADC_TypeDef *adc, const ADC_InitScan_TypeDef *init);
440 void ADC_InitSingle(ADC_TypeDef *adc, const ADC_InitSingle_TypeDef *init);
441 
442 /***************************************************************************//**
443  * @brief
444  *   Clear one or more pending ADC interrupts.
445  *
446  * @param[in] adc
447  *   Pointer to ADC peripheral register block.
448  *
449  * @param[in] flags
450  *   Pending ADC interrupt source to clear. Use a bitwise logic OR combination
451  *   of valid interrupt flags for the ADC module (ADC_IF_nnn).
452  ******************************************************************************/
ADC_IntClear(ADC_TypeDef * adc,uint32_t flags)453 __STATIC_INLINE void ADC_IntClear(ADC_TypeDef *adc, uint32_t flags)
454 {
455   adc->IFC = flags;
456 }
457 
458 
459 /***************************************************************************//**
460  * @brief
461  *   Disable one or more ADC interrupts.
462  *
463  * @param[in] adc
464  *   Pointer to ADC peripheral register block.
465  *
466  * @param[in] flags
467  *   ADC interrupt sources to disable. Use a bitwise logic OR combination of
468  *   valid interrupt flags for the ADC module (ADC_IF_nnn).
469  ******************************************************************************/
ADC_IntDisable(ADC_TypeDef * adc,uint32_t flags)470 __STATIC_INLINE void ADC_IntDisable(ADC_TypeDef *adc, uint32_t flags)
471 {
472   adc->IEN &= ~(flags);
473 }
474 
475 
476 /***************************************************************************//**
477  * @brief
478  *   Enable one or more ADC interrupts.
479  *
480  * @note
481  *   Depending on the use, a pending interrupt may already be set prior to
482  *   enabling the interrupt. Consider using ADC_IntClear() prior to enabling
483  *   if such a pending interrupt should be ignored.
484  *
485  * @param[in] adc
486  *   Pointer to ADC peripheral register block.
487  *
488  * @param[in] flags
489  *   ADC interrupt sources to enable. Use a bitwise logic OR combination of
490  *   valid interrupt flags for the ADC module (ADC_IF_nnn).
491  ******************************************************************************/
ADC_IntEnable(ADC_TypeDef * adc,uint32_t flags)492 __STATIC_INLINE void ADC_IntEnable(ADC_TypeDef *adc, uint32_t flags)
493 {
494   adc->IEN |= flags;
495 }
496 
497 
498 /***************************************************************************//**
499  * @brief
500  *   Get pending ADC interrupt flags.
501  *
502  * @note
503  *   The event bits are not cleared by the use of this function.
504  *
505  * @param[in] adc
506  *   Pointer to ADC peripheral register block.
507  *
508  * @return
509  *   ADC interrupt sources pending. A bitwise logic OR combination of valid
510  *   interrupt flags for the ADC module (ADC_IF_nnn).
511  ******************************************************************************/
ADC_IntGet(ADC_TypeDef * adc)512 __STATIC_INLINE uint32_t ADC_IntGet(ADC_TypeDef *adc)
513 {
514   return(adc->IF);
515 }
516 
517 
518 /***************************************************************************//**
519  * @brief
520  *   Set one or more pending ADC interrupts from SW.
521  *
522  * @param[in] adc
523  *   Pointer to ADC peripheral register block.
524  *
525  * @param[in] flags
526  *   ADC interrupt sources to set to pending. Use a bitwise logic OR combination
527  *   of valid interrupt flags for the ADC module (ADC_IF_nnn).
528  ******************************************************************************/
ADC_IntSet(ADC_TypeDef * adc,uint32_t flags)529 __STATIC_INLINE void ADC_IntSet(ADC_TypeDef *adc, uint32_t flags)
530 {
531   adc->IFS = flags;
532 }
533 
534 uint8_t ADC_PrescaleCalc(uint32_t adcFreq, uint32_t hfperFreq);
535 
536 
537 /***************************************************************************//**
538  * @brief
539  *   Start scan sequence and/or single conversion.
540  *
541  * @param[in] adc
542  *   Pointer to ADC peripheral register block.
543  *
544  * @param[in] cmd
545  *   Command indicating which type of sampling to start.
546  ******************************************************************************/
ADC_Start(ADC_TypeDef * adc,ADC_Start_TypeDef cmd)547 __STATIC_INLINE void ADC_Start(ADC_TypeDef *adc, ADC_Start_TypeDef cmd)
548 {
549   adc->CMD = (uint32_t)cmd;
550 }
551 
552 void ADC_Reset(ADC_TypeDef *adc);
553 uint8_t ADC_TimebaseCalc(uint32_t hfperFreq);
554 
555 /** @} (end addtogroup ADC) */
556 /** @} (end addtogroup EM_Library) */
557 
558 #ifdef __cplusplus
559 }
560 #endif
561 
562 #endif /* __EM_ADC_H */
563