1 /***************************************************************************//**
2  * @file
3  * @brief Analog Comparator (ACMP) 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_ACMP_H
34 #define __EM_ACMP_H
35 
36 #include <stdint.h>
37 #include <stdbool.h>
38 #include "em_part.h"
39 
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43 
44 /***************************************************************************//**
45  * @addtogroup EM_Library
46  * @{
47  ******************************************************************************/
48 
49 /***************************************************************************//**
50  * @addtogroup ACMP
51  * @{
52  ******************************************************************************/
53 
54 /*******************************************************************************
55  ********************************   ENUMS   ************************************
56  ******************************************************************************/
57 
58 /** Resistor values used for capacative sense. See the datasheet for your
59  *  device for details on each resistor value. */
60 typedef enum
61 {
62   /** resistor value 0 */
63   acmpResistor0 = _ACMP_INPUTSEL_CSRESSEL_RES0,
64   /** resistor value 1 */
65   acmpResistor1 = _ACMP_INPUTSEL_CSRESSEL_RES1,
66   /** resistor value 2 */
67   acmpResistor2 = _ACMP_INPUTSEL_CSRESSEL_RES2,
68   /** resistor value 3 */
69   acmpResistor3 = _ACMP_INPUTSEL_CSRESSEL_RES3
70 } ACMP_CapsenseResistor_TypeDef;
71 
72 /** Hysteresis level. See datasheet for your device for details on each
73  *  level. */
74 typedef enum
75 {
76   acmpHysteresisLevel0 = _ACMP_CTRL_HYSTSEL_HYST0, /**< Hysteresis level 0 */
77   acmpHysteresisLevel1 = _ACMP_CTRL_HYSTSEL_HYST1, /**< Hysteresis level 1 */
78   acmpHysteresisLevel2 = _ACMP_CTRL_HYSTSEL_HYST2, /**< Hysteresis level 2 */
79   acmpHysteresisLevel3 = _ACMP_CTRL_HYSTSEL_HYST3, /**< Hysteresis level 3 */
80   acmpHysteresisLevel4 = _ACMP_CTRL_HYSTSEL_HYST4, /**< Hysteresis level 4 */
81   acmpHysteresisLevel5 = _ACMP_CTRL_HYSTSEL_HYST5, /**< Hysteresis level 5 */
82   acmpHysteresisLevel6 = _ACMP_CTRL_HYSTSEL_HYST6, /**< Hysteresis level 6 */
83   acmpHysteresisLevel7 = _ACMP_CTRL_HYSTSEL_HYST7  /**< Hysteresis level 7 */
84 } ACMP_HysteresisLevel_TypeDef;
85 
86 /** ACMP warmup time. The delay is measured in HFPERCLK cycles and should
87  *  be at least 10 us. */
88 typedef enum
89 {
90   /** 4 HFPERCLK cycles warmup */
91   acmpWarmTime4   = _ACMP_CTRL_WARMTIME_4CYCLES,
92   /** 8 HFPERCLK cycles warmup */
93   acmpWarmTime8   = _ACMP_CTRL_WARMTIME_8CYCLES,
94   /** 16 HFPERCLK cycles warmup */
95   acmpWarmTime16  = _ACMP_CTRL_WARMTIME_16CYCLES,
96   /** 32 HFPERCLK cycles warmup */
97   acmpWarmTime32  = _ACMP_CTRL_WARMTIME_32CYCLES,
98   /** 64 HFPERCLK cycles warmup */
99   acmpWarmTime64  = _ACMP_CTRL_WARMTIME_64CYCLES,
100   /** 128 HFPERCLK cycles warmup */
101   acmpWarmTime128 = _ACMP_CTRL_WARMTIME_128CYCLES,
102   /** 256 HFPERCLK cycles warmup */
103   acmpWarmTime256 = _ACMP_CTRL_WARMTIME_256CYCLES,
104   /** 512 HFPERCLK cycles warmup */
105   acmpWarmTime512 = _ACMP_CTRL_WARMTIME_512CYCLES
106 } ACMP_WarmTime_TypeDef;
107 
108 /** ACMP inputs. Note that scaled VDD and bandgap references can only be used
109  *  as negative inputs. */
110 typedef enum
111 {
112   /** Channel 0 */
113   acmpChannel0    = _ACMP_INPUTSEL_NEGSEL_CH0,
114   /** Channel 1 */
115   acmpChannel1    = _ACMP_INPUTSEL_NEGSEL_CH1,
116   /** Channel 2 */
117   acmpChannel2    = _ACMP_INPUTSEL_NEGSEL_CH2,
118   /** Channel 3 */
119   acmpChannel3    = _ACMP_INPUTSEL_NEGSEL_CH3,
120   /** Channel 4 */
121   acmpChannel4    = _ACMP_INPUTSEL_NEGSEL_CH4,
122   /** Channel 5 */
123   acmpChannel5    = _ACMP_INPUTSEL_NEGSEL_CH5,
124   /** Channel 6 */
125   acmpChannel6    = _ACMP_INPUTSEL_NEGSEL_CH6,
126   /** Channel 7 */
127   acmpChannel7    = _ACMP_INPUTSEL_NEGSEL_CH7,
128   /** 1.25V internal reference */
129   acmpChannel1V25 = _ACMP_INPUTSEL_NEGSEL_1V25,
130   /** 2.5V internal reference */
131   acmpChannel2V5  = _ACMP_INPUTSEL_NEGSEL_2V5,
132   /** Scaled VDD reference */
133   acmpChannelVDD  = _ACMP_INPUTSEL_NEGSEL_VDD,
134 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_TINY_FAMILY)
135   /** DAC0 channel 0 */
136   acmpChannelDAC0Ch0 = _ACMP_INPUTSEL_NEGSEL_DAC0CH0,
137   /** DAC0 channel 1 */
138   acmpChannelDAC0Ch1 = _ACMP_INPUTSEL_NEGSEL_DAC0CH1,
139 #endif
140 } ACMP_Channel_TypeDef;
141 
142 /*******************************************************************************
143  ******************************   STRUCTS   ************************************
144  ******************************************************************************/
145 
146 /** Capsense initialization structure. */
147 typedef struct
148 {
149   /** Full bias current. See the ACMP chapter about bias and response time in
150    *  the reference manual for details. */
151   bool                          fullBias;
152 
153   /** Half bias current. See the ACMP chapter about bias and response time in
154    *  the reference manual for details. */
155   bool                          halfBias;
156 
157   /** Bias current. See the ACMP chapter about bias and response time in the
158    *  reference manual for details. Valid values are in the range 0-7. */
159   uint32_t                      biasProg;
160 
161   /** Warmup time. This is measured in HFPERCLK cycles and should be
162    *  about 10us in wall clock time. */
163   ACMP_WarmTime_TypeDef         warmTime;
164 
165   /** Hysteresis level */
166   ACMP_HysteresisLevel_TypeDef  hysteresisLevel;
167 
168   /** Resistor used in the capacative sensing circuit. For values see
169    *  your device datasheet. */
170   ACMP_CapsenseResistor_TypeDef resistor;
171 
172   /** Low power reference enabled. This setting, if enabled, reduces the
173    *  power used by the VDD and bandgap references. */
174   bool                          lowPowerReferenceEnabled;
175 
176   /** Vdd reference value. VDD_SCALED = VDD × VDDLEVEL × 50mV/3.8V.
177    *  Valid values are in the range 0-63. */
178   uint32_t                      vddLevel;
179 
180   /** If true, ACMP is being enabled after configuration. */
181   bool                          enable;
182 } ACMP_CapsenseInit_TypeDef;
183 
184 /** Default config for capacitive sense mode initialization. */
185 #define ACMP_CAPSENSE_INIT_DEFAULT                        \
186   { false,              /* fullBias */                    \
187     false,              /* halfBias */                    \
188     0x7,                /* biasProg */                    \
189     acmpWarmTime512,    /* 512 cycle warmup to be safe */ \
190     acmpHysteresisLevel5,                                 \
191     acmpResistor3,                                        \
192     false,              /* low power reference */         \
193     0x3D,               /* VDD level */                   \
194     true                /* Enable after init. */          \
195   }
196 
197 /** ACMP initialization structure. */
198 typedef struct
199 {
200   /** Full bias current. See the ACMP chapter about bias and response time in
201    *  the reference manual for details. */
202   bool                         fullBias;
203 
204   /** Half bias current. See the ACMP chapter about bias and response time in
205    *  the reference manual for details. */
206   bool                         halfBias;
207 
208   /** Bias current. See the ACMP chapter about bias and response time in the
209    *  reference manual for details. Valid values are in the range 0-7. */
210   uint32_t                     biasProg;
211 
212   /** Enable setting the interrupt flag on falling edge */
213   bool                         interruptOnFallingEdge;
214 
215   /** Enable setting the interrupt flag on rising edge */
216   bool                         interruptOnRisingEdge;
217 
218   /** Warmup time. This is measured in HFPERCLK cycles and should be
219    *  about 10us in wall clock time. */
220   ACMP_WarmTime_TypeDef        warmTime;
221 
222   /** Hysteresis level */
223   ACMP_HysteresisLevel_TypeDef hysteresisLevel;
224 
225   /** Inactive value emitted by the ACMP during warmup */
226   bool                         inactiveValue;
227 
228   /** Low power reference enabled. This setting, if enabled, reduces the
229    *  power used by the VDD and bandgap references. */
230   bool                         lowPowerReferenceEnabled;
231 
232   /** Vdd reference value. VDD_SCALED = VDD × VDDLEVEL × 50mV/3.8V.
233    *  Valid values are in the range 0-63. */
234   uint32_t                     vddLevel;
235 
236   /** If true, ACMP is being enabled after configuration. */
237   bool                         enable;
238 } ACMP_Init_TypeDef;
239 
240 /** Default config for ACMP regular initialization. */
241 #define ACMP_INIT_DEFAULT                                                     \
242   { false,              /* fullBias */                                        \
243     false,              /* halfBias */                                        \
244     0x7,                /* biasProg */                                        \
245     false,              /* No interrupt on falling edge. */                   \
246     false,              /* No interrupt on rising edge. */                    \
247     acmpWarmTime512,    /* 512 cycle warmup to be safe */                     \
248     acmpHysteresisLevel5,                                                     \
249     false,              /* Disabled emitting inactive value during warmup. */ \
250     false,              /* low power reference */                             \
251     0x3D,               /* VDD level */                                       \
252     true                /* Enable after init. */                              \
253   }
254 
255 
256 /*******************************************************************************
257  *****************************   PROTOTYPES   **********************************
258  ******************************************************************************/
259 
260 void ACMP_CapsenseInit(ACMP_TypeDef *acmp, const ACMP_CapsenseInit_TypeDef *init);
261 void ACMP_CapsenseChannelSet(ACMP_TypeDef *acmp, ACMP_Channel_TypeDef channel);
262 void ACMP_ChannelSet(ACMP_TypeDef *acmp, ACMP_Channel_TypeDef negSel, ACMP_Channel_TypeDef posSel);
263 void ACMP_Disable(ACMP_TypeDef *acmp);
264 void ACMP_Enable(ACMP_TypeDef *acmp);
265 void ACMP_GPIOSetup(ACMP_TypeDef *acmp, uint32_t location, bool enable, bool invert);
266 void ACMP_Init(ACMP_TypeDef *acmp, const ACMP_Init_TypeDef *init);
267 void ACMP_Reset(ACMP_TypeDef *acmp);
268 
269 /***************************************************************************//**
270  * @brief
271  *   Clear one or more pending ACMP interrupts.
272  *
273  * @param[in] acmp
274  *   Pointer to ACMP peripheral register block.
275  *
276  * @param[in] flags
277  *   Pending ACMP interrupt source to clear. Use a bitwise logic OR combination
278  *   of valid interrupt flags for the ACMP module (ACMP_IF_nnn).
279  ******************************************************************************/
ACMP_IntClear(ACMP_TypeDef * acmp,uint32_t flags)280 __STATIC_INLINE void ACMP_IntClear(ACMP_TypeDef *acmp, uint32_t flags)
281 {
282   acmp->IFC = flags;
283 }
284 
285 
286 /***************************************************************************//**
287  * @brief
288  *   Disable one or more ACMP interrupts.
289  *
290  * @param[in] acmp
291  *   Pointer to ACMP peripheral register block.
292  *
293  * @param[in] flags
294  *   ACMP interrupt sources to disable. Use a bitwise logic OR combination of
295  *   valid interrupt flags for the ACMP module (ACMP_IF_nnn).
296  ******************************************************************************/
ACMP_IntDisable(ACMP_TypeDef * acmp,uint32_t flags)297 __STATIC_INLINE void ACMP_IntDisable(ACMP_TypeDef *acmp, uint32_t flags)
298 {
299   acmp->IEN &= ~(flags);
300 }
301 
302 
303 /***************************************************************************//**
304  * @brief
305  *   Enable one or more ACMP interrupts.
306  *
307  * @note
308  *   Depending on the use, a pending interrupt may already be set prior to
309  *   enabling the interrupt. Consider using ACMP_IntClear() prior to enabling
310  *   if such a pending interrupt should be ignored.
311  *
312  * @param[in] acmp
313  *   Pointer to ACMP peripheral register block.
314  *
315  * @param[in] flags
316  *   ACMP interrupt sources to enable. Use a bitwise logic OR combination of
317  *   valid interrupt flags for the ACMP module (ACMP_IF_nnn).
318  ******************************************************************************/
ACMP_IntEnable(ACMP_TypeDef * acmp,uint32_t flags)319 __STATIC_INLINE void ACMP_IntEnable(ACMP_TypeDef *acmp, uint32_t flags)
320 {
321   acmp->IEN |= flags;
322 }
323 
324 
325 /***************************************************************************//**
326  * @brief
327  *   Get pending ACMP interrupt flags.
328  *
329  * @note
330  *   The event bits are not cleared by the use of this function.
331  *
332  * @param[in] acmp
333  *   Pointer to ACMP peripheral register block.
334  *
335  * @return
336  *   ACMP interrupt sources pending. A bitwise logic OR combination of valid
337  *   interrupt flags for the ACMP module (ACMP_IF_nnn).
338  ******************************************************************************/
ACMP_IntGet(ACMP_TypeDef * acmp)339 __STATIC_INLINE uint32_t ACMP_IntGet(ACMP_TypeDef *acmp)
340 {
341   return(acmp->IF);
342 }
343 
344 
345 /***************************************************************************//**
346  * @brief
347  *   Get enabled and pending ACMP interrupt flags.
348  *   Useful for handling more interrupt sources in the same interrupt handler.
349  *
350  * @param[in] usart
351  *   Pointer to ACMP peripheral register block.
352  *
353  * @note
354  *   Interrupt flags are not cleared by the use of this function.
355  *
356  * @return
357  *   Pending and enabled ACMP interrupt sources.
358  *   The return value is the bitwise AND combination of
359  *   - the OR combination of enabled interrupt sources in ACMPx_IEN_nnn
360  *     register (ACMPx_IEN_nnn) and
361  *   - the OR combination of valid interrupt flags of the ACMP module
362  *     (ACMPx_IF_nnn).
363  ******************************************************************************/
ACMP_IntGetEnabled(ACMP_TypeDef * acmp)364 __STATIC_INLINE uint32_t ACMP_IntGetEnabled(ACMP_TypeDef *acmp)
365 {
366   uint32_t tmp;
367 
368   /* Store ACMPx->IEN in temporary variable in order to define explicit order
369    * of volatile accesses. */
370   tmp = acmp->IEN;
371 
372   /* Bitwise AND of pending and enabled interrupts */
373   return acmp->IF & tmp;
374 }
375 
376 
377 /***************************************************************************//**
378  * @brief
379  *   Set one or more pending ACMP interrupts from SW.
380  *
381  * @param[in] acmp
382  *   Pointer to ACMP peripheral register block.
383  *
384  * @param[in] flags
385  *   ACMP interrupt sources to set to pending. Use a bitwise logic OR
386  *   combination of valid interrupt flags for the ACMP module (ACMP_IF_nnn).
387  ******************************************************************************/
ACMP_IntSet(ACMP_TypeDef * acmp,uint32_t flags)388 __STATIC_INLINE void ACMP_IntSet(ACMP_TypeDef *acmp, uint32_t flags)
389 {
390   acmp->IFS = flags;
391 }
392 
393 /** @} (end addtogroup ACMP) */
394 /** @} (end addtogroup EM_Library) */
395 
396 #ifdef __cplusplus
397 }
398 #endif
399 
400 #endif /* __EM_ACMP_H */
401