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 #include <stdbool.h>
34 #include "em_acmp.h"
35 #include "em_bitband.h"
36 #include "em_assert.h"
37
38 /***************************************************************************//**
39 * @addtogroup EM_Library
40 * @{
41 ******************************************************************************/
42
43 /***************************************************************************//**
44 * @addtogroup ACMP
45 * @brief Analog comparator (ACMP) Peripheral API
46 * @{
47 ******************************************************************************/
48
49 /*******************************************************************************
50 ******************************* DEFINES ***********************************
51 ******************************************************************************/
52
53 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
54
55
56 /** Validation of ACMP register block pointer reference
57 * for assert statements. */
58 #if (ACMP_COUNT == 1)
59 #define ACMP_REF_VALID(ref) ((ref) == ACMP0)
60 #elif (ACMP_COUNT == 2)
61 #define ACMP_REF_VALID(ref) (((ref) == ACMP0) || ((ref) == ACMP1))
62 #else
63 #error Undefined number of analog comparators (ACMP).
64 #endif
65
66 /** @endcond */
67
68 /*******************************************************************************
69 ************************** GLOBAL FUNCTIONS *******************************
70 ******************************************************************************/
71
72 /***************************************************************************//**
73 * @brief
74 * Sets up the ACMP for use in capacative sense applications.
75 *
76 * @details
77 * This function sets up the ACMP for use in capacacitve sense applications.
78 * To use the capacative sense functionality in the ACMP you need to use
79 * the PRS output of the ACMP module to count the number of oscillations
80 * in the capacative sense circuit (possibly using a TIMER).
81 *
82 * @note
83 * A basic example of capacative sensing can be found in the STK BSP
84 * (capsense demo).
85 *
86 * @param[in] acmp
87 * Pointer to ACMP peripheral register block.
88 *
89 * @param[in] init
90 * Pointer to initialization structure used to configure ACMP for capacative
91 * sensing operation.
92 ******************************************************************************/
ACMP_CapsenseInit(ACMP_TypeDef * acmp,const ACMP_CapsenseInit_TypeDef * init)93 void ACMP_CapsenseInit(ACMP_TypeDef *acmp, const ACMP_CapsenseInit_TypeDef *init)
94 {
95 /* Make sure the module exists on the selected chip */
96 EFM_ASSERT(ACMP_REF_VALID(acmp));
97
98 /* Make sure that vddLevel is within bounds */
99 EFM_ASSERT(init->vddLevel < 64);
100
101 /* Make sure biasprog is within bounds */
102 EFM_ASSERT(init->biasProg < 16);
103
104 /* Set control register. No need to set interrupt modes */
105 acmp->CTRL = (init->fullBias << _ACMP_CTRL_FULLBIAS_SHIFT)
106 | (init->halfBias << _ACMP_CTRL_HALFBIAS_SHIFT)
107 | (init->biasProg << _ACMP_CTRL_BIASPROG_SHIFT)
108 | (init->warmTime << _ACMP_CTRL_WARMTIME_SHIFT)
109 | (init->hysteresisLevel << _ACMP_CTRL_HYSTSEL_SHIFT);
110
111 /* Select capacative sensing mode by selecting a resistor and enabling it */
112 acmp->INPUTSEL = (init->resistor << _ACMP_INPUTSEL_CSRESSEL_SHIFT)
113 | ACMP_INPUTSEL_CSRESEN
114 | (init->lowPowerReferenceEnabled << _ACMP_INPUTSEL_LPREF_SHIFT)
115 | (init->vddLevel << _ACMP_INPUTSEL_VDDLEVEL_SHIFT)
116 | ACMP_INPUTSEL_NEGSEL_CAPSENSE;
117
118 /* Enable ACMP if requested.
119 * Note: BITBAND_Peripheral() function is used for setting/clearing single
120 * bit peripheral register bitfields. */
121 BITBAND_Peripheral(&(acmp->CTRL),
122 (uint32_t)_ACMP_CTRL_EN_SHIFT,
123 (uint32_t)init->enable);
124 }
125
126 /***************************************************************************//**
127 * @brief
128 * Sets the ACMP channel used for capacative sensing.
129 *
130 * @note
131 * A basic example of capacative sensing can be found in the STK BSP
132 * (capsense demo).
133 *
134 * @param[in] acmp
135 * Pointer to ACMP peripheral register block.
136 *
137 * @param[in] channel
138 * The ACMP channel to use for capacative sensing (Possel).
139 ******************************************************************************/
ACMP_CapsenseChannelSet(ACMP_TypeDef * acmp,ACMP_Channel_TypeDef channel)140 void ACMP_CapsenseChannelSet(ACMP_TypeDef *acmp, ACMP_Channel_TypeDef channel)
141 {
142 /* Make sure that only external channels are used */
143 EFM_ASSERT(channel < _ACMP_INPUTSEL_NEGSEL_1V25);
144
145 /* Set channel as positive channel in ACMP */
146 SET_BIT_FIELD(acmp->INPUTSEL, _ACMP_INPUTSEL_POSSEL_MASK, channel,
147 _ACMP_INPUTSEL_POSSEL_SHIFT);
148 }
149
150 /***************************************************************************//**
151 * @brief
152 * Disables the ACMP.
153 *
154 * @param[in] acmp
155 * Pointer to ACMP peripheral register block.
156 ******************************************************************************/
ACMP_Disable(ACMP_TypeDef * acmp)157 void ACMP_Disable(ACMP_TypeDef *acmp)
158 {
159 acmp->CTRL &= ~ACMP_CTRL_EN;
160 }
161
162 /***************************************************************************//**
163 * @brief
164 * Enables the ACMP.
165 *
166 * @param[in] acmp
167 * Pointer to ACMP peripheral register block.
168 ******************************************************************************/
ACMP_Enable(ACMP_TypeDef * acmp)169 void ACMP_Enable(ACMP_TypeDef *acmp)
170 {
171 acmp->CTRL |= ACMP_CTRL_EN;
172 }
173
174 /***************************************************************************//**
175 * @brief
176 * Reset ACMP to same state as after a HW reset.
177 *
178 * @note
179 * The ROUTE register is NOT reset by this function, in order to allow for
180 * centralized setup of this feature.
181 *
182 * @param[in] acmp
183 * Pointer to the ACMP peripheral register block.
184 ******************************************************************************/
ACMP_Reset(ACMP_TypeDef * acmp)185 void ACMP_Reset(ACMP_TypeDef *acmp)
186 {
187 /* Make sure the module exists on the selected chip */
188 EFM_ASSERT(ACMP_REF_VALID(acmp));
189
190 acmp->CTRL = _ACMP_CTRL_RESETVALUE;
191 acmp->INPUTSEL = _ACMP_INPUTSEL_RESETVALUE;
192 acmp->IEN = _ACMP_IEN_RESETVALUE;
193 acmp->IFC = _ACMP_IF_MASK;
194 }
195
196 /***************************************************************************//**
197 * @brief
198 * Sets up GPIO output from the ACMP.
199 *
200 * @note
201 * GPIO must be enabled in the CMU before this function call, i.e.
202 * @verbatim CMU_ClockEnable(cmuClock_GPIO, true); @endverbatim
203 *
204 * @param[in] acmp
205 * Pointer to the ACMP peripheral register block.
206 *
207 * @param location
208 * The pin location to use. See the datasheet for location to pin mappings.
209 *
210 * @param enable
211 * Enable or disable pin output.
212 *
213 * @param invert
214 * Invert output.
215 ******************************************************************************/
ACMP_GPIOSetup(ACMP_TypeDef * acmp,uint32_t location,bool enable,bool invert)216 void ACMP_GPIOSetup(ACMP_TypeDef *acmp, uint32_t location, bool enable, bool invert)
217 {
218 /* Sanity checking of location */
219 EFM_ASSERT(location < 4);
220
221 /* Set GPIO inversion */
222 SET_BIT_FIELD(acmp->CTRL, _ACMP_CTRL_GPIOINV_MASK, invert,
223 _ACMP_CTRL_GPIOINV_SHIFT);
224
225 acmp->ROUTE = (location << _ACMP_ROUTE_LOCATION_SHIFT)
226 | (enable << _ACMP_ROUTE_ACMPPEN_SHIFT);
227 }
228
229 /***************************************************************************//**
230 * @brief
231 * Sets which channels should be used in ACMP comparisons.
232 *
233 * @param[in] acmp
234 * Pointer to the ACMP peripheral register block.
235 *
236 * @param negSel
237 * Channel to use on the negative input to the ACMP.
238 *
239 * @param posSel
240 * Channel to use on the positive input to the ACMP.
241 ******************************************************************************/
ACMP_ChannelSet(ACMP_TypeDef * acmp,ACMP_Channel_TypeDef negSel,ACMP_Channel_TypeDef posSel)242 void ACMP_ChannelSet(ACMP_TypeDef *acmp, ACMP_Channel_TypeDef negSel,
243 ACMP_Channel_TypeDef posSel)
244 {
245 /* Make sure that only external channels are used as ACMP positive input */
246 EFM_ASSERT(posSel < _ACMP_INPUTSEL_NEGSEL_1V25);
247 /* Sanity checking of ACMP negative input */
248 EFM_ASSERT(negSel <= _ACMP_INPUTSEL_NEGSEL_VDD);
249
250 acmp->INPUTSEL = (acmp->INPUTSEL & ~(_ACMP_INPUTSEL_POSSEL_MASK |
251 _ACMP_INPUTSEL_NEGSEL_MASK))
252 | (negSel << _ACMP_INPUTSEL_NEGSEL_SHIFT)
253 | (posSel << _ACMP_INPUTSEL_POSSEL_SHIFT);
254 }
255
256 /***************************************************************************//**
257 * @brief
258 *
259 *
260 * @param[in] acmp
261 * Pointer to the ACMP peripheral register block.
262 *
263 * @param[in] init
264 * Pointer to initialization structure used to configure ACMP for capacative
265 * sensing operation.
266 ******************************************************************************/
ACMP_Init(ACMP_TypeDef * acmp,const ACMP_Init_TypeDef * init)267 void ACMP_Init(ACMP_TypeDef *acmp, const ACMP_Init_TypeDef *init)
268 {
269 /* Make sure the module exists on the selected chip */
270 EFM_ASSERT(ACMP_REF_VALID(acmp));
271
272 /* Make sure biasprog is within bounds */
273 EFM_ASSERT(init->biasProg < 16);
274
275 /* Set control register. No need to set interrupt modes */
276 acmp->CTRL = (init->fullBias << _ACMP_CTRL_FULLBIAS_SHIFT)
277 | (init->halfBias << _ACMP_CTRL_HALFBIAS_SHIFT)
278 | (init->biasProg << _ACMP_CTRL_BIASPROG_SHIFT)
279 | (init->interruptOnFallingEdge << _ACMP_CTRL_IFALL_SHIFT)
280 | (init->interruptOnRisingEdge << _ACMP_CTRL_IRISE_SHIFT)
281 | (init->warmTime << _ACMP_CTRL_WARMTIME_SHIFT)
282 | (init->hysteresisLevel << _ACMP_CTRL_HYSTSEL_SHIFT)
283 | (init->inactiveValue << _ACMP_CTRL_INACTVAL_SHIFT);
284
285 acmp->INPUTSEL = (init->lowPowerReferenceEnabled << _ACMP_INPUTSEL_LPREF_SHIFT)
286 | (init->vddLevel << _ACMP_INPUTSEL_VDDLEVEL_SHIFT);
287
288 /* Enable ACMP if requested.
289 * Note: BITBAND_Peripheral() function is used for setting/clearing single
290 * bit peripheral register bitfields. */
291 BITBAND_Peripheral(&(acmp->CTRL),
292 (uint32_t)_ACMP_CTRL_EN_SHIFT,
293 (uint32_t)init->enable);
294 }
295
296
297 /** @} (end addtogroup ACMP) */
298 /** @} (end addtogroup EM_Library) */
299